blob: 85dd821892a2c453e7705a612d05bf972270a460 [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 Hutchins627c7f92013-10-11 21:55:33 +000054static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000055 // Find the source location of the last statement in the block, if the block
56 // is not empty.
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000057 if (const Stmt *StmtNode = Block->getTerminator()) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000058 return StmtNode->getLocStart();
59 } else {
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000060 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
61 BE = Block->rend(); BI != BE; ++BI) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000062 // 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.
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000069 assert(Block->pred_size() == 1 && *Block->pred_begin() &&
70 Block->succ_size() != 0);
DeLesley Hutchins73858402013-10-09 18:30:24 +000071
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000072 return getLastStmtLoc(*Block->pred_begin());
DeLesley Hutchins73858402013-10-09 18:30:24 +000073}
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;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000343 void forwardInfo(const Stmt *From, const Stmt *To);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000344 void handleTestingFunctionCall(const CallExpr *Call, const VarDecl *Var);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000345 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000346 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
347 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000348
349public:
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000350 void checkCallability(const PropagationInfo &PInfo,
351 const FunctionDecl *FunDecl,
352 SourceLocation BlameLoc);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000353
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000354 void Visit(const Stmt *StmtNode);
355
356 void VisitBinaryOperator(const BinaryOperator *BinOp);
357 void VisitCallExpr(const CallExpr *Call);
358 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000359 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000360 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,
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000392 SourceLocation BlameLoc) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000393
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(),
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000410 stateToString(VarState), BlameLoc);
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(
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000420 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000421 }
422}
423
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000424void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
425 InfoEntry Entry = PropagationMap.find(From);
426
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000427 if (Entry != PropagationMap.end())
428 PropagationMap.insert(PairType(To, Entry->second));
429}
430
431void ConsumedStmtVisitor::handleTestingFunctionCall(const CallExpr *Call,
432 const VarDecl *Var) {
433
434 ConsumedState VarState = StateMap->getState(Var);
435
436 if (VarState != CS_Unknown) {
437 SourceLocation CallLoc = Call->getExprLoc();
438
439 if (!CallLoc.isMacroID())
440 Analyzer.WarningsHandler.warnUnnecessaryTest(Var->getNameAsString(),
441 stateToString(VarState), CallLoc);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000442 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000443
444 PropagationMap.insert(PairType(Call, PropagationInfo(Var, CS_Unconsumed)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000445}
446
447bool ConsumedStmtVisitor::isLikeMoveAssignment(
448 const CXXMethodDecl *MethodDecl) {
449
450 return MethodDecl->isMoveAssignmentOperator() ||
451 (MethodDecl->getOverloadedOperator() == OO_Equal &&
452 MethodDecl->getNumParams() == 1 &&
453 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
454}
455
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000456void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
457 const FunctionDecl *Fun,
458 QualType ReturnType) {
459 if (isConsumableType(ReturnType)) {
460
461 ConsumedState ReturnState;
462
463 if (Fun->hasAttr<ReturnTypestateAttr>())
464 ReturnState = mapReturnTypestateAttrState(
465 Fun->getAttr<ReturnTypestateAttr>());
466 else
David Blaikiea33ab602013-09-06 01:28:43 +0000467 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000468
469 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000470 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000471 }
472}
473
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000474void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
475
476 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
477
478 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
479 CE = StmtNode->child_end(); CI != CE; ++CI) {
480
481 PropagationMap.erase(*CI);
482 }
483}
484
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000485void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
486 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000487 case BO_LAnd:
488 case BO_LOr : {
489 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
490 REntry = PropagationMap.find(BinOp->getRHS());
491
492 VarTestResult LTest, RTest;
493
494 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
495 LTest = LEntry->second.getTest();
496
497 } else {
498 LTest.Var = NULL;
499 LTest.TestsFor = CS_None;
500 }
501
502 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
503 RTest = REntry->second.getTest();
504
505 } else {
506 RTest.Var = NULL;
507 RTest.TestsFor = CS_None;
508 }
509
510 if (!(LTest.Var == NULL && RTest.Var == NULL))
511 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
512 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
513
514 break;
515 }
516
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000517 case BO_PtrMemD:
518 case BO_PtrMemI:
519 forwardInfo(BinOp->getLHS(), BinOp);
520 break;
521
522 default:
523 break;
524 }
525}
526
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000527void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
528 if (const FunctionDecl *FunDecl =
529 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
530
531 // Special case for the std::move function.
532 // TODO: Make this more specific. (Deferred)
533 if (FunDecl->getNameAsString() == "move") {
534 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
535
536 if (Entry != PropagationMap.end()) {
537 PropagationMap.insert(PairType(Call, Entry->second));
538 }
539
540 return;
541 }
542
543 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
544
545 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
546 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
547
548 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
549
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000550 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000551 continue;
552 }
553
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000554 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000555
556 if (ParamType->isRValueReferenceType() ||
557 (ParamType->isLValueReferenceType() &&
558 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
559
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000560 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000561
562 } else if (!(ParamType.isConstQualified() ||
563 ((ParamType->isReferenceType() ||
564 ParamType->isPointerType()) &&
565 ParamType->getPointeeType().isConstQualified()))) {
566
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000567 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000568 }
569 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000570
DeLesley Hutchins66540852013-10-04 21:28:06 +0000571 QualType RetType = FunDecl->getCallResultType();
572 if (RetType->isReferenceType())
573 RetType = RetType->getPointeeType();
574
575 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000576 }
577}
578
579void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000580 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000581}
582
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000583void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
584 const CXXBindTemporaryExpr *Temp) {
585
586 forwardInfo(Temp->getSubExpr(), Temp);
587}
588
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000589void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
590 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000591
592 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000593 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
594
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000595 if (isConsumableType(ThisType)) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000596 if (Constructor->isDefaultConstructor()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000597
598 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000599 PropagationInfo(consumed::CS_Consumed, ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000600
601 } else if (Constructor->isMoveConstructor()) {
602
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000603 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000604 PropagationMap.find(Call->getArg(0))->second;
605
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000606 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000607 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000608
609 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000610 PropagationInfo(StateMap->getState(Var), ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000611
612 StateMap->setState(Var, consumed::CS_Consumed);
613
614 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000615 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000616 }
617
618 } else if (Constructor->isCopyConstructor()) {
619 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
620
621 if (Entry != PropagationMap.end())
622 PropagationMap.insert(PairType(Call, Entry->second));
623
624 } else {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000625 propagateReturnType(Call, Constructor, ThisType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000626 }
627 }
628}
629
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000630
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000631void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
632 const CXXMemberCallExpr *Call) {
633
634 VisitCallExpr(Call);
635
636 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
637
638 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000639 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000640 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000641
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000642 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000643
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000644 if (PInfo.isVar()) {
645 if (isTestingFunction(MethodDecl))
646 handleTestingFunctionCall(Call, PInfo.getVar());
647 else if (MethodDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000648 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000649 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000650 }
651}
652
653void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
654 const CXXOperatorCallExpr *Call) {
655
656 const FunctionDecl *FunDecl =
657 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
658
659 if (!FunDecl) return;
660
661 if (isa<CXXMethodDecl>(FunDecl) &&
662 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
663
664 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
665 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
666
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000667 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000668
669 if (LEntry != PropagationMap.end() &&
670 REntry != PropagationMap.end()) {
671
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000672 LPInfo = LEntry->second;
673 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000674
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000675 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000676 StateMap->setState(LPInfo.getVar(),
677 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000678
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000679 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000680
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000681 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000682
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000683 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000684 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000685
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000686 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000687
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000688 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000689 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000690 PropagationInfo(StateMap->getState(RPInfo.getVar()),
691 LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000692
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000693 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000694
695 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000696 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000697 }
698
699 } else if (LEntry != PropagationMap.end() &&
700 REntry == PropagationMap.end()) {
701
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000702 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000703
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000704 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000705 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000706
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000707 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000708
DeLesley Hutchins66540852013-10-04 21:28:06 +0000709 } else if (LPInfo.isState()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000710 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000711 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000712 }
713
714 } else if (LEntry == PropagationMap.end() &&
715 REntry != PropagationMap.end()) {
716
DeLesley Hutchins66540852013-10-04 21:28:06 +0000717 if (REntry->second.isVar())
718 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000719 }
720
721 } else {
722
723 VisitCallExpr(Call);
724
725 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
726
727 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000728 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000729
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000730 checkCallability(PInfo, FunDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000731
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000732 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000733 if (isTestingFunction(FunDecl))
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000734 handleTestingFunctionCall(Call, PInfo.getVar());
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000735 else if (FunDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000736 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000737 }
738 }
739 }
740}
741
742void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
743 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
744 if (StateMap->getState(Var) != consumed::CS_None)
745 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
746}
747
748void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
749 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
750 DE = DeclS->decl_end(); DI != DE; ++DI) {
751
752 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
753 }
754
755 if (DeclS->isSingleDecl())
756 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
757 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
758}
759
760void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
761 const MaterializeTemporaryExpr *Temp) {
762
763 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
764
765 if (Entry != PropagationMap.end())
766 PropagationMap.insert(PairType(Temp, Entry->second));
767}
768
769void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
770 forwardInfo(MExpr->getBase(), MExpr);
771}
772
DeLesley Hutchins42525982013-08-29 22:36:05 +0000773
774void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000775 QualType ParamType = Param->getType();
776 ConsumedState ParamState = consumed::CS_None;
777
778 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
779 isConsumableType(ParamType))
780 ParamState = mapConsumableAttrState(ParamType);
781 else if (ParamType->isReferenceType() &&
782 isConsumableType(ParamType->getPointeeType()))
783 ParamState = consumed::CS_Unknown;
784
785 if (ParamState)
786 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000787}
788
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000789void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
790 if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) {
791 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
792
793 if (Entry != PropagationMap.end()) {
794 assert(Entry->second.isState() || Entry->second.isVar());
795
796 ConsumedState RetState = Entry->second.isState() ?
797 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
798
799 if (RetState != ExpectedState)
800 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
801 Ret->getReturnLoc(), stateToString(ExpectedState),
802 stateToString(RetState));
803 }
804 }
805}
806
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000807void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000808 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
809 if (Entry == PropagationMap.end()) return;
810
811 switch (UOp->getOpcode()) {
812 case UO_AddrOf:
813 PropagationMap.insert(PairType(UOp, Entry->second));
814 break;
815
816 case UO_LNot:
817 if (Entry->second.isTest() || Entry->second.isBinTest())
818 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
819 break;
820
821 default:
822 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000823 }
824}
825
DeLesley Hutchins66540852013-10-04 21:28:06 +0000826// TODO: See if I need to check for reference types here.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000827void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000828 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000829 if (Var->hasInit()) {
830 PropagationInfo PInfo =
831 PropagationMap.find(Var->getInit())->second;
832
833 StateMap->setState(Var, PInfo.isVar() ?
834 StateMap->getState(PInfo.getVar()) : PInfo.getState());
835
836 } else {
837 StateMap->setState(Var, consumed::CS_Unknown);
838 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000839 }
840}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000841}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000842
843namespace clang {
844namespace consumed {
845
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000846void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
847 ConsumedStateMap *ThenStates,
848 ConsumedStateMap *ElseStates) {
849
850 ConsumedState VarState = ThenStates->getState(Test.Var);
851
852 if (VarState == CS_Unknown) {
853 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins66540852013-10-04 21:28:06 +0000854 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000855
856 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
857 ThenStates->markUnreachable();
858
DeLesley Hutchins66540852013-10-04 21:28:06 +0000859 } else if (VarState == Test.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000860 ElseStates->markUnreachable();
861 }
862}
863
864void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
865 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
866
867 const VarTestResult &LTest = PInfo.getLTest(),
868 &RTest = PInfo.getRTest();
869
870 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
871 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
872
873 if (LTest.Var) {
874 if (PInfo.testEffectiveOp() == EO_And) {
875 if (LState == CS_Unknown) {
876 ThenStates->setState(LTest.Var, LTest.TestsFor);
877
878 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
879 ThenStates->markUnreachable();
880
881 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000882 if (RState == RTest.TestsFor)
883 ElseStates->markUnreachable();
884 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000885 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000886 }
887
888 } else {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000889 if (LState == CS_Unknown) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000890 ElseStates->setState(LTest.Var,
891 invertConsumedUnconsumed(LTest.TestsFor));
892
DeLesley Hutchins66540852013-10-04 21:28:06 +0000893 } else if (LState == LTest.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000894 ElseStates->markUnreachable();
895
896 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
897 isKnownState(RState)) {
898
DeLesley Hutchins66540852013-10-04 21:28:06 +0000899 if (RState == RTest.TestsFor)
900 ElseStates->markUnreachable();
901 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000902 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000903 }
904 }
905 }
906
907 if (RTest.Var) {
908 if (PInfo.testEffectiveOp() == EO_And) {
909 if (RState == CS_Unknown)
910 ThenStates->setState(RTest.Var, RTest.TestsFor);
911 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
912 ThenStates->markUnreachable();
913
DeLesley Hutchins66540852013-10-04 21:28:06 +0000914 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000915 if (RState == CS_Unknown)
916 ElseStates->setState(RTest.Var,
917 invertConsumedUnconsumed(RTest.TestsFor));
918 else if (RState == RTest.TestsFor)
919 ElseStates->markUnreachable();
920 }
921 }
922}
923
DeLesley Hutchins73858402013-10-09 18:30:24 +0000924bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
925 const CFGBlock *TargetBlock) {
926
927 assert(CurrBlock && "Block pointer must not be NULL");
928 assert(TargetBlock && "TargetBlock pointer must not be NULL");
929
930 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
931 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
932 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
933 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
934 return false;
935 }
936 return true;
937}
938
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000939void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
940 ConsumedStateMap *StateMap,
941 bool &AlreadyOwned) {
942
DeLesley Hutchins73858402013-10-09 18:30:24 +0000943 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000944
945 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
946
947 if (Entry) {
948 Entry->intersect(StateMap);
949
950 } else if (AlreadyOwned) {
951 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
952
953 } else {
954 StateMapsArray[Block->getBlockID()] = StateMap;
955 AlreadyOwned = true;
956 }
957}
958
959void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
960 ConsumedStateMap *StateMap) {
961
DeLesley Hutchins73858402013-10-09 18:30:24 +0000962 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000963
964 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
965
966 if (Entry) {
967 Entry->intersect(StateMap);
968 delete StateMap;
969
970 } else {
971 StateMapsArray[Block->getBlockID()] = StateMap;
972 }
973}
974
DeLesley Hutchins73858402013-10-09 18:30:24 +0000975ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
976 assert(Block && "Block pointer must not be NULL");
977 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
978
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000979 return StateMapsArray[Block->getBlockID()];
980}
981
DeLesley Hutchins73858402013-10-09 18:30:24 +0000982void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
983 unsigned int BlockID = Block->getBlockID();
984 delete StateMapsArray[BlockID];
985 StateMapsArray[BlockID] = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000986}
987
DeLesley Hutchins73858402013-10-09 18:30:24 +0000988ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
989 assert(Block && "Block pointer must not be NULL");
990
991 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
992 if (isBackEdgeTarget(Block)) {
993 return new ConsumedStateMap(*StateMap);
994 } else {
995 StateMapsArray[Block->getBlockID()] = NULL;
996 return StateMap;
997 }
998}
999
1000bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1001 assert(From && "From block must not be NULL");
1002 assert(To && "From block must not be NULL");
1003
1004 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1005}
1006
1007bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1008 assert(Block != NULL && "Block pointer must not be NULL");
1009
1010 // Anything with less than two predecessors can't be the target of a back
1011 // edge.
1012 if (Block->pred_size() < 2)
1013 return false;
1014
1015 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1016 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1017 PE = Block->pred_end(); PI != PE; ++PI) {
1018 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1019 return true;
1020 }
1021 return false;
1022}
1023
1024ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001025 MapType::const_iterator Entry = Map.find(Var);
1026
1027 if (Entry != Map.end()) {
1028 return Entry->second;
1029
1030 } else {
1031 return CS_None;
1032 }
1033}
1034
1035void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1036 ConsumedState LocalState;
1037
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001038 if (this->From && this->From == Other->From && !Other->Reachable) {
1039 this->markUnreachable();
1040 return;
1041 }
1042
DeLesley Hutchins73858402013-10-09 18:30:24 +00001043 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1044 DMI != DME; ++DMI) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001045
1046 LocalState = this->getState(DMI->first);
1047
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001048 if (LocalState == CS_None)
1049 continue;
1050
1051 if (LocalState != DMI->second)
1052 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001053 }
1054}
1055
DeLesley Hutchins73858402013-10-09 18:30:24 +00001056void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1057 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1058 ConsumedWarningsHandlerBase &WarningsHandler) {
1059
1060 ConsumedState LocalState;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001061 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001062
1063 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1064 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1065
1066 LocalState = this->getState(DMI->first);
1067
1068 if (LocalState == CS_None)
1069 continue;
1070
1071 if (LocalState != DMI->second) {
1072 Map[DMI->first] = CS_Unknown;
1073 WarningsHandler.warnLoopStateMismatch(
1074 BlameLoc, DMI->first->getNameAsString());
1075 }
1076 }
1077}
1078
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001079void ConsumedStateMap::markUnreachable() {
1080 this->Reachable = false;
1081 Map.clear();
1082}
1083
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001084void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1085 Map[Var] = State;
1086}
1087
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001088void ConsumedStateMap::remove(const VarDecl *Var) {
1089 Map.erase(Var);
1090}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001091
DeLesley Hutchins73858402013-10-09 18:30:24 +00001092bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1093 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1094 DMI != DME; ++DMI) {
1095
1096 if (this->getState(DMI->first) != DMI->second)
1097 return true;
1098 }
1099
1100 return false;
1101}
1102
David Blaikiea33ab602013-09-06 01:28:43 +00001103void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1104 const FunctionDecl *D) {
1105 QualType ReturnType;
1106 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1107 ASTContext &CurrContext = AC.getASTContext();
1108 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1109 } else
1110 ReturnType = D->getCallResultType();
1111
1112 if (D->hasAttr<ReturnTypestateAttr>()) {
1113 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1114
1115 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1116 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1117 // FIXME: This should be removed when template instantiation propagates
1118 // attributes at template specialization definition, not
1119 // declaration. When it is removed the test needs to be enabled
1120 // in SemaDeclAttr.cpp.
1121 WarningsHandler.warnReturnTypestateForUnconsumableType(
1122 RTSAttr->getLocation(), ReturnType.getAsString());
1123 ExpectedReturnState = CS_None;
1124 } else
1125 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1126 } else if (isConsumableType(ReturnType))
1127 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1128 else
1129 ExpectedReturnState = CS_None;
1130}
1131
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001132bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1133 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001134
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001135 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1136 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001137
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001138 if (const IfStmt *IfNode =
1139 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001140
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001141 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001142
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001143 PInfo = Visitor.getInfo(Cond);
1144 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1145 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1146
1147 if (PInfo.isTest()) {
1148 CurrStates->setSource(Cond);
1149 FalseStates->setSource(Cond);
DeLesley Hutchins66540852013-10-04 21:28:06 +00001150 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001151
1152 } else if (PInfo.isBinTest()) {
1153 CurrStates->setSource(PInfo.testSourceNode());
1154 FalseStates->setSource(PInfo.testSourceNode());
DeLesley Hutchins66540852013-10-04 21:28:06 +00001155 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001156
1157 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001158 delete FalseStates;
1159 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001160 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001161
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001162 } else if (const BinaryOperator *BinOp =
1163 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1164
1165 PInfo = Visitor.getInfo(BinOp->getLHS());
1166 if (!PInfo.isTest()) {
1167 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1168 PInfo = Visitor.getInfo(BinOp->getRHS());
1169
1170 if (!PInfo.isTest()) {
1171 delete FalseStates;
1172 return false;
1173 }
1174
1175 } else {
1176 delete FalseStates;
1177 return false;
1178 }
1179 }
1180
1181 CurrStates->setSource(BinOp);
1182 FalseStates->setSource(BinOp);
1183
1184 const VarTestResult &Test = PInfo.getTest();
1185 ConsumedState VarState = CurrStates->getState(Test.Var);
1186
1187 if (BinOp->getOpcode() == BO_LAnd) {
1188 if (VarState == CS_Unknown)
1189 CurrStates->setState(Test.Var, Test.TestsFor);
1190 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1191 CurrStates->markUnreachable();
1192
1193 } else if (BinOp->getOpcode() == BO_LOr) {
1194 if (VarState == CS_Unknown)
1195 FalseStates->setState(Test.Var,
1196 invertConsumedUnconsumed(Test.TestsFor));
1197 else if (VarState == Test.TestsFor)
1198 FalseStates->markUnreachable();
1199 }
1200
1201 } else {
1202 delete FalseStates;
1203 return false;
1204 }
1205
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001206 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1207
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001208 if (*SI)
1209 BlockInfo.addInfo(*SI, CurrStates);
1210 else
1211 delete CurrStates;
1212
1213 if (*++SI)
1214 BlockInfo.addInfo(*SI, FalseStates);
1215 else
1216 delete FalseStates;
1217
1218 CurrStates = NULL;
1219 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001220}
1221
1222void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1223 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001224 if (!D)
1225 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001226
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001227 CFG *CFGraph = AC.getCFG();
1228 if (!CFGraph)
1229 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001230
David Blaikiea33ab602013-09-06 01:28:43 +00001231 determineExpectedReturnState(AC, D);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001232
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001233 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins73858402013-10-09 18:30:24 +00001234 // AC.getCFG()->viewCFG(LangOptions());
1235
1236 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001237
1238 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001239 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1240
1241 // Add all trackable parameters to the state map.
1242 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1243 PE = D->param_end(); PI != PE; ++PI) {
1244 Visitor.VisitParmVarDecl(*PI);
1245 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001246
1247 // Visit all of the function's basic blocks.
1248 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1249 E = SortedGraph->end(); I != E; ++I) {
1250
1251 const CFGBlock *CurrBlock = *I;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001252
1253 if (CurrStates == NULL)
1254 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001255
1256 if (!CurrStates) {
1257 continue;
1258
1259 } else if (!CurrStates->isReachable()) {
1260 delete CurrStates;
1261 CurrStates = NULL;
1262 continue;
1263 }
1264
1265 Visitor.reset(CurrStates);
1266
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001267 // Visit all of the basic block's statements.
1268 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1269 BE = CurrBlock->end(); BI != BE; ++BI) {
1270
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001271 switch (BI->getKind()) {
1272 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001273 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001274 break;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001275
1276 case CFGElement::TemporaryDtor: {
1277 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1278 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1279 PropagationInfo PInfo = Visitor.getInfo(BTE);
1280
1281 if (PInfo.isValid())
1282 Visitor.checkCallability(PInfo,
1283 DTor.getDestructorDecl(AC.getASTContext()),
1284 BTE->getExprLoc());
1285 break;
1286 }
1287
1288 case CFGElement::AutomaticObjectDtor: {
1289 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1290
1291 const VarDecl *Var = DTor.getVarDecl();
1292 ConsumedState VarState = CurrStates->getState(Var);
1293
1294 if (VarState != CS_None) {
1295 PropagationInfo PInfo(Var);
1296
1297 Visitor.checkCallability(PInfo,
1298 DTor.getDestructorDecl(AC.getASTContext()),
1299 getLastStmtLoc(CurrBlock));
1300
1301 CurrStates->remove(Var);
1302 }
1303 break;
1304 }
1305
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001306 default:
1307 break;
1308 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001309 }
1310
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001311 // TODO: Handle other forms of branching with precision, including while-
1312 // and for-loops. (Deferred)
1313 if (!splitState(CurrBlock, Visitor)) {
1314 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001315
DeLesley Hutchins73858402013-10-09 18:30:24 +00001316 if (CurrBlock->succ_size() > 1 ||
1317 (CurrBlock->succ_size() == 1 &&
1318 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001319
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001320 bool OwnershipTaken = false;
1321
1322 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1323 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1324
DeLesley Hutchins73858402013-10-09 18:30:24 +00001325 if (*SI == NULL) continue;
1326
1327 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1328 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1329 CurrStates,
1330 WarningsHandler);
1331
1332 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1333 BlockInfo.discardInfo(*SI);
1334 } else {
1335 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1336 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001337 }
1338
1339 if (!OwnershipTaken)
1340 delete CurrStates;
1341
1342 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001343 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001344 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001345 } // End of block iterator.
1346
1347 // Delete the last existing state map.
1348 delete CurrStates;
1349
1350 WarningsHandler.emitDiagnostics();
1351}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001352}} // end namespace clang::consumed