blob: d291f627d0249ef9f2fd702539375c2aeaedfe5d [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 Hutchins73858402013-10-09 18:30:24 +000034// TODO: Use information from tests in while-loop conditional.
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +000035// TODO: Add notes about the actual and expected state for
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000036// TODO: Correctly identify unreachable blocks when chaining boolean operators.
DeLesley Hutchins66540852013-10-04 21:28:06 +000037// TODO: Adjust the parser and AttributesList class to support lists of
38// identifiers.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000039// TODO: Warn about unreachable code.
40// TODO: Switch to using a bitmap to track unreachable blocks.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000041// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
42// if (valid) ...; (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000043// TODO: Take notes on state transitions to provide better warning messages.
44// (Deferred)
45// TODO: Test nested conditionals: A) Checking the same value multiple times,
46// and 2) Checking different values. (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000047
48using namespace clang;
49using namespace consumed;
50
51// Key method definition
52ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
53
DeLesley Hutchins73858402013-10-09 18:30:24 +000054static SourceLocation getWarningLocForLoopExit(const CFGBlock *ExitBlock) {
55 // Find the source location of the last statement in the block, if the block
56 // is not empty.
57 if (const Stmt *StmtNode = ExitBlock->getTerminator()) {
58 return StmtNode->getLocStart();
59 } else {
60 for (CFGBlock::const_reverse_iterator BI = ExitBlock->rbegin(),
61 BE = ExitBlock->rend(); BI != BE; ++BI) {
62 // FIXME: Handle other CFGElement kinds.
63 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
64 return CS->getStmt()->getLocStart();
65 }
66 }
67
68 // The block is empty, and has a single predecessor. Use its exit location.
69 assert(ExitBlock->pred_size() == 1 && *ExitBlock->pred_begin() &&
70 ExitBlock->succ_size() != 0);
71
72 return getWarningLocForLoopExit(*ExitBlock->pred_begin());
73}
74
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000075static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
76 switch (State) {
77 case CS_Unconsumed:
78 return CS_Consumed;
79 case CS_Consumed:
80 return CS_Unconsumed;
81 case CS_None:
82 return CS_None;
83 case CS_Unknown:
84 return CS_Unknown;
85 }
86 llvm_unreachable("invalid enum");
87}
88
DeLesley Hutchins66540852013-10-04 21:28:06 +000089static bool isCallableInState(const CallableWhenAttr *CWAttr,
90 ConsumedState State) {
91
92 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
93 E = CWAttr->callableState_end();
94
95 for (; I != E; ++I) {
96
97 ConsumedState MappedAttrState = CS_None;
98
99 switch (*I) {
100 case CallableWhenAttr::Unknown:
101 MappedAttrState = CS_Unknown;
102 break;
103
104 case CallableWhenAttr::Unconsumed:
105 MappedAttrState = CS_Unconsumed;
106 break;
107
108 case CallableWhenAttr::Consumed:
109 MappedAttrState = CS_Consumed;
110 break;
111 }
112
113 if (MappedAttrState == State)
114 return true;
115 }
116
117 return false;
118}
119
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000120static bool isConsumableType(const QualType &QT) {
121 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
122 return RD->hasAttr<ConsumableAttr>();
123 else
124 return false;
125}
126
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000127static bool isKnownState(ConsumedState State) {
128 switch (State) {
129 case CS_Unconsumed:
130 case CS_Consumed:
131 return true;
132 case CS_None:
133 case CS_Unknown:
134 return false;
135 }
Aaron Ballman6b2ec032013-08-29 20:36:09 +0000136 llvm_unreachable("invalid enum");
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000137}
138
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000139static bool isTestingFunction(const FunctionDecl *FunDecl) {
140 return FunDecl->hasAttr<TestsUnconsumedAttr>();
141}
142
David Blaikiea33ab602013-09-06 01:28:43 +0000143static ConsumedState mapConsumableAttrState(const QualType QT) {
144 assert(isConsumableType(QT));
145
146 const ConsumableAttr *CAttr =
147 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
148
149 switch (CAttr->getDefaultState()) {
150 case ConsumableAttr::Unknown:
151 return CS_Unknown;
152 case ConsumableAttr::Unconsumed:
153 return CS_Unconsumed;
154 case ConsumableAttr::Consumed:
155 return CS_Consumed;
156 }
157 llvm_unreachable("invalid enum");
158}
159
Eric Christophere988dc42013-09-03 20:43:00 +0000160static ConsumedState
161mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000162 switch (RTSAttr->getState()) {
163 case ReturnTypestateAttr::Unknown:
164 return CS_Unknown;
165 case ReturnTypestateAttr::Unconsumed:
166 return CS_Unconsumed;
167 case ReturnTypestateAttr::Consumed:
168 return CS_Consumed;
169 }
Eric Christophere988dc42013-09-03 20:43:00 +0000170 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000171}
172
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000173static StringRef stateToString(ConsumedState State) {
174 switch (State) {
175 case consumed::CS_None:
176 return "none";
177
178 case consumed::CS_Unknown:
179 return "unknown";
180
181 case consumed::CS_Unconsumed:
182 return "unconsumed";
183
184 case consumed::CS_Consumed:
185 return "consumed";
186 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000187 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000188}
189
190namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000191struct VarTestResult {
192 const VarDecl *Var;
193 ConsumedState TestsFor;
194};
195} // end anonymous::VarTestResult
196
197namespace clang {
198namespace consumed {
199
200enum EffectiveOp {
201 EO_And,
202 EO_Or
203};
204
205class PropagationInfo {
206 enum {
207 IT_None,
208 IT_State,
209 IT_Test,
210 IT_BinTest,
211 IT_Var
212 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000213
214 struct BinTestTy {
215 const BinaryOperator *Source;
216 EffectiveOp EOp;
217 VarTestResult LTest;
218 VarTestResult RTest;
219 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000220
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000221 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000222 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000223 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000224 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000225 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000226 };
227
DeLesley Hutchins66540852013-10-04 21:28:06 +0000228 QualType TempType;
229
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000230public:
231 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000232
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000233 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
234 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
235 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000236
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000237 Test.Var = Var;
238 Test.TestsFor = TestsFor;
239 }
240
241 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
242 const VarTestResult &LTest, const VarTestResult &RTest)
243 : InfoType(IT_BinTest) {
244
245 BinTest.Source = Source;
246 BinTest.EOp = EOp;
247 BinTest.LTest = LTest;
248 BinTest.RTest = RTest;
249 }
250
251 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
252 const VarDecl *LVar, ConsumedState LTestsFor,
253 const VarDecl *RVar, ConsumedState RTestsFor)
254 : InfoType(IT_BinTest) {
255
256 BinTest.Source = Source;
257 BinTest.EOp = EOp;
258 BinTest.LTest.Var = LVar;
259 BinTest.LTest.TestsFor = LTestsFor;
260 BinTest.RTest.Var = RVar;
261 BinTest.RTest.TestsFor = RTestsFor;
262 }
263
DeLesley Hutchins66540852013-10-04 21:28:06 +0000264 PropagationInfo(ConsumedState State, QualType TempType)
265 : InfoType(IT_State), State(State), TempType(TempType) {}
266
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000267 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
268
269 const ConsumedState & getState() const {
270 assert(InfoType == IT_State);
271 return State;
272 }
273
DeLesley Hutchins66540852013-10-04 21:28:06 +0000274 const QualType & getTempType() const {
275 assert(InfoType == IT_State);
276 return TempType;
277 }
278
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000279 const VarTestResult & getTest() const {
280 assert(InfoType == IT_Test);
281 return Test;
282 }
283
284 const VarTestResult & getLTest() const {
285 assert(InfoType == IT_BinTest);
286 return BinTest.LTest;
287 }
288
289 const VarTestResult & getRTest() const {
290 assert(InfoType == IT_BinTest);
291 return BinTest.RTest;
292 }
293
294 const VarDecl * getVar() const {
295 assert(InfoType == IT_Var);
296 return Var;
297 }
298
299 EffectiveOp testEffectiveOp() const {
300 assert(InfoType == IT_BinTest);
301 return BinTest.EOp;
302 }
303
304 const BinaryOperator * testSourceNode() const {
305 assert(InfoType == IT_BinTest);
306 return BinTest.Source;
307 }
308
309 bool isValid() const { return InfoType != IT_None; }
310 bool isState() const { return InfoType == IT_State; }
311 bool isTest() const { return InfoType == IT_Test; }
312 bool isBinTest() const { return InfoType == IT_BinTest; }
313 bool isVar() const { return InfoType == IT_Var; }
314
315 PropagationInfo invertTest() const {
316 assert(InfoType == IT_Test || InfoType == IT_BinTest);
317
318 if (InfoType == IT_Test) {
319 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
320
321 } else if (InfoType == IT_BinTest) {
322 return PropagationInfo(BinTest.Source,
323 BinTest.EOp == EO_And ? EO_Or : EO_And,
324 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
325 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
326 } else {
327 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000328 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000329 }
330};
331
332class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000333
334 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
335 typedef std::pair<const Stmt *, PropagationInfo> PairType;
336 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000337 typedef MapType::const_iterator ConstInfoEntry;
338
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000339 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000340 ConsumedAnalyzer &Analyzer;
341 ConsumedStateMap *StateMap;
342 MapType PropagationMap;
343
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000344 void checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000345 const FunctionDecl *FunDecl,
346 const CallExpr *Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000347 void forwardInfo(const Stmt *From, const Stmt *To);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000348 void handleTestingFunctionCall(const CallExpr *Call, const VarDecl *Var);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000349 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000350 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
351 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000352
353public:
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000354
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000355 void Visit(const Stmt *StmtNode);
356
357 void VisitBinaryOperator(const BinaryOperator *BinOp);
358 void VisitCallExpr(const CallExpr *Call);
359 void VisitCastExpr(const CastExpr *Cast);
360 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
361 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
362 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
363 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
364 void VisitDeclStmt(const DeclStmt *DelcS);
365 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
366 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000367 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000368 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000369 void VisitUnaryOperator(const UnaryOperator *UOp);
370 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000371
DeLesley Hutchins42525982013-08-29 22:36:05 +0000372 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
373 ConsumedStateMap *StateMap)
374 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000375
376 PropagationInfo getInfo(const Stmt *StmtNode) const {
377 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
378
379 if (Entry != PropagationMap.end())
380 return Entry->second;
381 else
382 return PropagationInfo();
383 }
384
385 void reset(ConsumedStateMap *NewStateMap) {
386 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000387 }
388};
389
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000390void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000391 const FunctionDecl *FunDecl,
392 const CallExpr *Call) {
393
DeLesley Hutchins66540852013-10-04 21:28:06 +0000394 if (!FunDecl->hasAttr<CallableWhenAttr>())
395 return;
396
397 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000398
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000399 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000400 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins66540852013-10-04 21:28:06 +0000401 ConsumedState VarState = StateMap->getState(Var);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000402
DeLesley Hutchins66540852013-10-04 21:28:06 +0000403 assert(VarState != CS_None && "Invalid state");
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000404
DeLesley Hutchins66540852013-10-04 21:28:06 +0000405 if (isCallableInState(CWAttr, VarState))
406 return;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000407
DeLesley Hutchins66540852013-10-04 21:28:06 +0000408 Analyzer.WarningsHandler.warnUseInInvalidState(
409 FunDecl->getNameAsString(), Var->getNameAsString(),
410 stateToString(VarState), Call->getExprLoc());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000411
DeLesley Hutchins66540852013-10-04 21:28:06 +0000412 } else if (PInfo.isState()) {
413
414 assert(PInfo.getState() != CS_None && "Invalid state");
415
416 if (isCallableInState(CWAttr, PInfo.getState()))
417 return;
418
419 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
420 FunDecl->getNameAsString(), stateToString(PInfo.getState()),
421 Call->getExprLoc());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000422 }
423}
424
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000425void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
426 InfoEntry Entry = PropagationMap.find(From);
427
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000428 if (Entry != PropagationMap.end())
429 PropagationMap.insert(PairType(To, Entry->second));
430}
431
432void ConsumedStmtVisitor::handleTestingFunctionCall(const CallExpr *Call,
433 const VarDecl *Var) {
434
435 ConsumedState VarState = StateMap->getState(Var);
436
437 if (VarState != CS_Unknown) {
438 SourceLocation CallLoc = Call->getExprLoc();
439
440 if (!CallLoc.isMacroID())
441 Analyzer.WarningsHandler.warnUnnecessaryTest(Var->getNameAsString(),
442 stateToString(VarState), CallLoc);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000443 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000444
445 PropagationMap.insert(PairType(Call, PropagationInfo(Var, CS_Unconsumed)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000446}
447
448bool ConsumedStmtVisitor::isLikeMoveAssignment(
449 const CXXMethodDecl *MethodDecl) {
450
451 return MethodDecl->isMoveAssignmentOperator() ||
452 (MethodDecl->getOverloadedOperator() == OO_Equal &&
453 MethodDecl->getNumParams() == 1 &&
454 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
455}
456
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000457void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
458 const FunctionDecl *Fun,
459 QualType ReturnType) {
460 if (isConsumableType(ReturnType)) {
461
462 ConsumedState ReturnState;
463
464 if (Fun->hasAttr<ReturnTypestateAttr>())
465 ReturnState = mapReturnTypestateAttrState(
466 Fun->getAttr<ReturnTypestateAttr>());
467 else
David Blaikiea33ab602013-09-06 01:28:43 +0000468 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000469
470 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000471 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000472 }
473}
474
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000475void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
476
477 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
478
479 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
480 CE = StmtNode->child_end(); CI != CE; ++CI) {
481
482 PropagationMap.erase(*CI);
483 }
484}
485
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000486void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
487 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000488 case BO_LAnd:
489 case BO_LOr : {
490 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
491 REntry = PropagationMap.find(BinOp->getRHS());
492
493 VarTestResult LTest, RTest;
494
495 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
496 LTest = LEntry->second.getTest();
497
498 } else {
499 LTest.Var = NULL;
500 LTest.TestsFor = CS_None;
501 }
502
503 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
504 RTest = REntry->second.getTest();
505
506 } else {
507 RTest.Var = NULL;
508 RTest.TestsFor = CS_None;
509 }
510
511 if (!(LTest.Var == NULL && RTest.Var == NULL))
512 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
513 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
514
515 break;
516 }
517
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000518 case BO_PtrMemD:
519 case BO_PtrMemI:
520 forwardInfo(BinOp->getLHS(), BinOp);
521 break;
522
523 default:
524 break;
525 }
526}
527
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000528void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
529 if (const FunctionDecl *FunDecl =
530 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
531
532 // Special case for the std::move function.
533 // TODO: Make this more specific. (Deferred)
534 if (FunDecl->getNameAsString() == "move") {
535 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
536
537 if (Entry != PropagationMap.end()) {
538 PropagationMap.insert(PairType(Call, Entry->second));
539 }
540
541 return;
542 }
543
544 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
545
546 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
547 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
548
549 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
550
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000551 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000552 continue;
553 }
554
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000555 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000556
557 if (ParamType->isRValueReferenceType() ||
558 (ParamType->isLValueReferenceType() &&
559 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
560
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000561 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000562
563 } else if (!(ParamType.isConstQualified() ||
564 ((ParamType->isReferenceType() ||
565 ParamType->isPointerType()) &&
566 ParamType->getPointeeType().isConstQualified()))) {
567
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000568 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000569 }
570 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000571
DeLesley Hutchins66540852013-10-04 21:28:06 +0000572 QualType RetType = FunDecl->getCallResultType();
573 if (RetType->isReferenceType())
574 RetType = RetType->getPointeeType();
575
576 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000577 }
578}
579
580void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000581 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000582}
583
584void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
585 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000586
587 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000588 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
589
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000590 if (isConsumableType(ThisType)) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000591 if (Constructor->isDefaultConstructor()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000592
593 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000594 PropagationInfo(consumed::CS_Consumed, ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000595
596 } else if (Constructor->isMoveConstructor()) {
597
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000598 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000599 PropagationMap.find(Call->getArg(0))->second;
600
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000601 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000602 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000603
604 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000605 PropagationInfo(StateMap->getState(Var), ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000606
607 StateMap->setState(Var, consumed::CS_Consumed);
608
609 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000610 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000611 }
612
613 } else if (Constructor->isCopyConstructor()) {
614 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
615
616 if (Entry != PropagationMap.end())
617 PropagationMap.insert(PairType(Call, Entry->second));
618
619 } else {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000620 propagateReturnType(Call, Constructor, ThisType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000621 }
622 }
623}
624
625void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
626 const CXXMemberCallExpr *Call) {
627
628 VisitCallExpr(Call);
629
630 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
631
632 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000633 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000634 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000635
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000636 checkCallability(PInfo, MethodDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000637
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000638 if (PInfo.isVar()) {
639 if (isTestingFunction(MethodDecl))
640 handleTestingFunctionCall(Call, PInfo.getVar());
641 else if (MethodDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000642 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000643 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000644 }
645}
646
647void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
648 const CXXOperatorCallExpr *Call) {
649
650 const FunctionDecl *FunDecl =
651 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
652
653 if (!FunDecl) return;
654
655 if (isa<CXXMethodDecl>(FunDecl) &&
656 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
657
658 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
659 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
660
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000661 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000662
663 if (LEntry != PropagationMap.end() &&
664 REntry != PropagationMap.end()) {
665
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000666 LPInfo = LEntry->second;
667 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000668
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000669 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000670 StateMap->setState(LPInfo.getVar(),
671 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000672
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000673 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000674
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000675 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000676
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000677 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000678 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000679
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000680 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000681
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000682 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000683 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000684 PropagationInfo(StateMap->getState(RPInfo.getVar()),
685 LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000686
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000687 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000688
689 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000690 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000691 }
692
693 } else if (LEntry != PropagationMap.end() &&
694 REntry == PropagationMap.end()) {
695
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000696 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000697
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000698 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000699 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000700
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000701 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000702
DeLesley Hutchins66540852013-10-04 21:28:06 +0000703 } else if (LPInfo.isState()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000704 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000705 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000706 }
707
708 } else if (LEntry == PropagationMap.end() &&
709 REntry != PropagationMap.end()) {
710
DeLesley Hutchins66540852013-10-04 21:28:06 +0000711 if (REntry->second.isVar())
712 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000713 }
714
715 } else {
716
717 VisitCallExpr(Call);
718
719 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
720
721 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000722 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000723
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000724 checkCallability(PInfo, FunDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000725
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000726 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000727 if (isTestingFunction(FunDecl))
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000728 handleTestingFunctionCall(Call, PInfo.getVar());
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000729 else if (FunDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000730 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000731 }
732 }
733 }
734}
735
736void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
737 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
738 if (StateMap->getState(Var) != consumed::CS_None)
739 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
740}
741
742void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
743 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
744 DE = DeclS->decl_end(); DI != DE; ++DI) {
745
746 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
747 }
748
749 if (DeclS->isSingleDecl())
750 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
751 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
752}
753
754void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
755 const MaterializeTemporaryExpr *Temp) {
756
757 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
758
759 if (Entry != PropagationMap.end())
760 PropagationMap.insert(PairType(Temp, Entry->second));
761}
762
763void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
764 forwardInfo(MExpr->getBase(), MExpr);
765}
766
DeLesley Hutchins42525982013-08-29 22:36:05 +0000767
768void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000769 QualType ParamType = Param->getType();
770 ConsumedState ParamState = consumed::CS_None;
771
772 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
773 isConsumableType(ParamType))
774 ParamState = mapConsumableAttrState(ParamType);
775 else if (ParamType->isReferenceType() &&
776 isConsumableType(ParamType->getPointeeType()))
777 ParamState = consumed::CS_Unknown;
778
779 if (ParamState)
780 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000781}
782
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000783void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
784 if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) {
785 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
786
787 if (Entry != PropagationMap.end()) {
788 assert(Entry->second.isState() || Entry->second.isVar());
789
790 ConsumedState RetState = Entry->second.isState() ?
791 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
792
793 if (RetState != ExpectedState)
794 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
795 Ret->getReturnLoc(), stateToString(ExpectedState),
796 stateToString(RetState));
797 }
798 }
799}
800
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000801void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000802 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
803 if (Entry == PropagationMap.end()) return;
804
805 switch (UOp->getOpcode()) {
806 case UO_AddrOf:
807 PropagationMap.insert(PairType(UOp, Entry->second));
808 break;
809
810 case UO_LNot:
811 if (Entry->second.isTest() || Entry->second.isBinTest())
812 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
813 break;
814
815 default:
816 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000817 }
818}
819
DeLesley Hutchins66540852013-10-04 21:28:06 +0000820// TODO: See if I need to check for reference types here.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000821void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000822 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000823 if (Var->hasInit()) {
824 PropagationInfo PInfo =
825 PropagationMap.find(Var->getInit())->second;
826
827 StateMap->setState(Var, PInfo.isVar() ?
828 StateMap->getState(PInfo.getVar()) : PInfo.getState());
829
830 } else {
831 StateMap->setState(Var, consumed::CS_Unknown);
832 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000833 }
834}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000835}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000836
837namespace clang {
838namespace consumed {
839
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000840void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
841 ConsumedStateMap *ThenStates,
842 ConsumedStateMap *ElseStates) {
843
844 ConsumedState VarState = ThenStates->getState(Test.Var);
845
846 if (VarState == CS_Unknown) {
847 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins66540852013-10-04 21:28:06 +0000848 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000849
850 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
851 ThenStates->markUnreachable();
852
DeLesley Hutchins66540852013-10-04 21:28:06 +0000853 } else if (VarState == Test.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000854 ElseStates->markUnreachable();
855 }
856}
857
858void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
859 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
860
861 const VarTestResult &LTest = PInfo.getLTest(),
862 &RTest = PInfo.getRTest();
863
864 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
865 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
866
867 if (LTest.Var) {
868 if (PInfo.testEffectiveOp() == EO_And) {
869 if (LState == CS_Unknown) {
870 ThenStates->setState(LTest.Var, LTest.TestsFor);
871
872 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
873 ThenStates->markUnreachable();
874
875 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000876 if (RState == RTest.TestsFor)
877 ElseStates->markUnreachable();
878 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000879 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000880 }
881
882 } else {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000883 if (LState == CS_Unknown) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000884 ElseStates->setState(LTest.Var,
885 invertConsumedUnconsumed(LTest.TestsFor));
886
DeLesley Hutchins66540852013-10-04 21:28:06 +0000887 } else if (LState == LTest.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000888 ElseStates->markUnreachable();
889
890 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
891 isKnownState(RState)) {
892
DeLesley Hutchins66540852013-10-04 21:28:06 +0000893 if (RState == RTest.TestsFor)
894 ElseStates->markUnreachable();
895 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000896 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000897 }
898 }
899 }
900
901 if (RTest.Var) {
902 if (PInfo.testEffectiveOp() == EO_And) {
903 if (RState == CS_Unknown)
904 ThenStates->setState(RTest.Var, RTest.TestsFor);
905 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
906 ThenStates->markUnreachable();
907
DeLesley Hutchins66540852013-10-04 21:28:06 +0000908 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000909 if (RState == CS_Unknown)
910 ElseStates->setState(RTest.Var,
911 invertConsumedUnconsumed(RTest.TestsFor));
912 else if (RState == RTest.TestsFor)
913 ElseStates->markUnreachable();
914 }
915 }
916}
917
DeLesley Hutchins73858402013-10-09 18:30:24 +0000918bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
919 const CFGBlock *TargetBlock) {
920
921 assert(CurrBlock && "Block pointer must not be NULL");
922 assert(TargetBlock && "TargetBlock pointer must not be NULL");
923
924 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
925 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
926 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
927 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
928 return false;
929 }
930 return true;
931}
932
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000933void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
934 ConsumedStateMap *StateMap,
935 bool &AlreadyOwned) {
936
DeLesley Hutchins73858402013-10-09 18:30:24 +0000937 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000938
939 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
940
941 if (Entry) {
942 Entry->intersect(StateMap);
943
944 } else if (AlreadyOwned) {
945 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
946
947 } else {
948 StateMapsArray[Block->getBlockID()] = StateMap;
949 AlreadyOwned = true;
950 }
951}
952
953void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
954 ConsumedStateMap *StateMap) {
955
DeLesley Hutchins73858402013-10-09 18:30:24 +0000956 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000957
958 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
959
960 if (Entry) {
961 Entry->intersect(StateMap);
962 delete StateMap;
963
964 } else {
965 StateMapsArray[Block->getBlockID()] = StateMap;
966 }
967}
968
DeLesley Hutchins73858402013-10-09 18:30:24 +0000969ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
970 assert(Block && "Block pointer must not be NULL");
971 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
972
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000973 return StateMapsArray[Block->getBlockID()];
974}
975
DeLesley Hutchins73858402013-10-09 18:30:24 +0000976void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
977 unsigned int BlockID = Block->getBlockID();
978 delete StateMapsArray[BlockID];
979 StateMapsArray[BlockID] = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000980}
981
DeLesley Hutchins73858402013-10-09 18:30:24 +0000982ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
983 assert(Block && "Block pointer must not be NULL");
984
985 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
986 if (isBackEdgeTarget(Block)) {
987 return new ConsumedStateMap(*StateMap);
988 } else {
989 StateMapsArray[Block->getBlockID()] = NULL;
990 return StateMap;
991 }
992}
993
994bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
995 assert(From && "From block must not be NULL");
996 assert(To && "From block must not be NULL");
997
998 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
999}
1000
1001bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1002 assert(Block != NULL && "Block pointer must not be NULL");
1003
1004 // Anything with less than two predecessors can't be the target of a back
1005 // edge.
1006 if (Block->pred_size() < 2)
1007 return false;
1008
1009 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1010 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1011 PE = Block->pred_end(); PI != PE; ++PI) {
1012 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1013 return true;
1014 }
1015 return false;
1016}
1017
1018ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001019 MapType::const_iterator Entry = Map.find(Var);
1020
1021 if (Entry != Map.end()) {
1022 return Entry->second;
1023
1024 } else {
1025 return CS_None;
1026 }
1027}
1028
1029void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1030 ConsumedState LocalState;
1031
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001032 if (this->From && this->From == Other->From && !Other->Reachable) {
1033 this->markUnreachable();
1034 return;
1035 }
1036
DeLesley Hutchins73858402013-10-09 18:30:24 +00001037 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1038 DMI != DME; ++DMI) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001039
1040 LocalState = this->getState(DMI->first);
1041
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001042 if (LocalState == CS_None)
1043 continue;
1044
1045 if (LocalState != DMI->second)
1046 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001047 }
1048}
1049
DeLesley Hutchins73858402013-10-09 18:30:24 +00001050void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1051 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1052 ConsumedWarningsHandlerBase &WarningsHandler) {
1053
1054 ConsumedState LocalState;
1055 SourceLocation BlameLoc = getWarningLocForLoopExit(LoopBack);
1056
1057 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1058 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1059
1060 LocalState = this->getState(DMI->first);
1061
1062 if (LocalState == CS_None)
1063 continue;
1064
1065 if (LocalState != DMI->second) {
1066 Map[DMI->first] = CS_Unknown;
1067 WarningsHandler.warnLoopStateMismatch(
1068 BlameLoc, DMI->first->getNameAsString());
1069 }
1070 }
1071}
1072
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001073void ConsumedStateMap::markUnreachable() {
1074 this->Reachable = false;
1075 Map.clear();
1076}
1077
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001078void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1079 Map[Var] = State;
1080}
1081
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001082void ConsumedStateMap::remove(const VarDecl *Var) {
1083 Map.erase(Var);
1084}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001085
DeLesley Hutchins73858402013-10-09 18:30:24 +00001086bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1087 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1088 DMI != DME; ++DMI) {
1089
1090 if (this->getState(DMI->first) != DMI->second)
1091 return true;
1092 }
1093
1094 return false;
1095}
1096
David Blaikiea33ab602013-09-06 01:28:43 +00001097void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1098 const FunctionDecl *D) {
1099 QualType ReturnType;
1100 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1101 ASTContext &CurrContext = AC.getASTContext();
1102 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1103 } else
1104 ReturnType = D->getCallResultType();
1105
1106 if (D->hasAttr<ReturnTypestateAttr>()) {
1107 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1108
1109 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1110 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1111 // FIXME: This should be removed when template instantiation propagates
1112 // attributes at template specialization definition, not
1113 // declaration. When it is removed the test needs to be enabled
1114 // in SemaDeclAttr.cpp.
1115 WarningsHandler.warnReturnTypestateForUnconsumableType(
1116 RTSAttr->getLocation(), ReturnType.getAsString());
1117 ExpectedReturnState = CS_None;
1118 } else
1119 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1120 } else if (isConsumableType(ReturnType))
1121 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1122 else
1123 ExpectedReturnState = CS_None;
1124}
1125
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001126bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1127 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001128
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001129 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1130 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001131
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001132 if (const IfStmt *IfNode =
1133 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001134
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001135 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001136
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001137 PInfo = Visitor.getInfo(Cond);
1138 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1139 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1140
1141 if (PInfo.isTest()) {
1142 CurrStates->setSource(Cond);
1143 FalseStates->setSource(Cond);
DeLesley Hutchins66540852013-10-04 21:28:06 +00001144 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001145
1146 } else if (PInfo.isBinTest()) {
1147 CurrStates->setSource(PInfo.testSourceNode());
1148 FalseStates->setSource(PInfo.testSourceNode());
DeLesley Hutchins66540852013-10-04 21:28:06 +00001149 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001150
1151 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001152 delete FalseStates;
1153 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001154 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001155
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001156 } else if (const BinaryOperator *BinOp =
1157 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1158
1159 PInfo = Visitor.getInfo(BinOp->getLHS());
1160 if (!PInfo.isTest()) {
1161 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1162 PInfo = Visitor.getInfo(BinOp->getRHS());
1163
1164 if (!PInfo.isTest()) {
1165 delete FalseStates;
1166 return false;
1167 }
1168
1169 } else {
1170 delete FalseStates;
1171 return false;
1172 }
1173 }
1174
1175 CurrStates->setSource(BinOp);
1176 FalseStates->setSource(BinOp);
1177
1178 const VarTestResult &Test = PInfo.getTest();
1179 ConsumedState VarState = CurrStates->getState(Test.Var);
1180
1181 if (BinOp->getOpcode() == BO_LAnd) {
1182 if (VarState == CS_Unknown)
1183 CurrStates->setState(Test.Var, Test.TestsFor);
1184 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1185 CurrStates->markUnreachable();
1186
1187 } else if (BinOp->getOpcode() == BO_LOr) {
1188 if (VarState == CS_Unknown)
1189 FalseStates->setState(Test.Var,
1190 invertConsumedUnconsumed(Test.TestsFor));
1191 else if (VarState == Test.TestsFor)
1192 FalseStates->markUnreachable();
1193 }
1194
1195 } else {
1196 delete FalseStates;
1197 return false;
1198 }
1199
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001200 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1201
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001202 if (*SI)
1203 BlockInfo.addInfo(*SI, CurrStates);
1204 else
1205 delete CurrStates;
1206
1207 if (*++SI)
1208 BlockInfo.addInfo(*SI, FalseStates);
1209 else
1210 delete FalseStates;
1211
1212 CurrStates = NULL;
1213 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001214}
1215
1216void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1217 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001218 if (!D)
1219 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001220
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001221 CFG *CFGraph = AC.getCFG();
1222 if (!CFGraph)
1223 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001224
David Blaikiea33ab602013-09-06 01:28:43 +00001225 determineExpectedReturnState(AC, D);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001226
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001227 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins73858402013-10-09 18:30:24 +00001228 // AC.getCFG()->viewCFG(LangOptions());
1229
1230 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001231
1232 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001233 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1234
1235 // Add all trackable parameters to the state map.
1236 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1237 PE = D->param_end(); PI != PE; ++PI) {
1238 Visitor.VisitParmVarDecl(*PI);
1239 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001240
1241 // Visit all of the function's basic blocks.
1242 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1243 E = SortedGraph->end(); I != E; ++I) {
1244
1245 const CFGBlock *CurrBlock = *I;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001246
1247 if (CurrStates == NULL)
1248 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001249
1250 if (!CurrStates) {
1251 continue;
1252
1253 } else if (!CurrStates->isReachable()) {
1254 delete CurrStates;
1255 CurrStates = NULL;
1256 continue;
1257 }
1258
1259 Visitor.reset(CurrStates);
1260
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001261 // Visit all of the basic block's statements.
1262 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1263 BE = CurrBlock->end(); BI != BE; ++BI) {
1264
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001265 switch (BI->getKind()) {
1266 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001267 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001268 break;
1269 case CFGElement::AutomaticObjectDtor:
1270 CurrStates->remove(BI->castAs<CFGAutomaticObjDtor>().getVarDecl());
1271 default:
1272 break;
1273 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001274 }
1275
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001276 // TODO: Handle other forms of branching with precision, including while-
1277 // and for-loops. (Deferred)
1278 if (!splitState(CurrBlock, Visitor)) {
1279 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001280
DeLesley Hutchins73858402013-10-09 18:30:24 +00001281 if (CurrBlock->succ_size() > 1 ||
1282 (CurrBlock->succ_size() == 1 &&
1283 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001284
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001285 bool OwnershipTaken = false;
1286
1287 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1288 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1289
DeLesley Hutchins73858402013-10-09 18:30:24 +00001290 if (*SI == NULL) continue;
1291
1292 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1293 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1294 CurrStates,
1295 WarningsHandler);
1296
1297 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1298 BlockInfo.discardInfo(*SI);
1299 } else {
1300 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1301 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001302 }
1303
1304 if (!OwnershipTaken)
1305 delete CurrStates;
1306
1307 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001308 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001309 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001310 } // End of block iterator.
1311
1312 // Delete the last existing state map.
1313 delete CurrStates;
1314
1315 WarningsHandler.emitDiagnostics();
1316}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001317}} // end namespace clang::consumed