blob: b06fb155d5b8ec06720c200c33be840d8c1157d0 [file] [log] [blame]
DeLesley Hutchins48a31762013-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 Hutchins48a31762013-08-12 21:20:55 +000029#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/SmallVector.h"
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000031#include "llvm/Support/Compiler.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000032#include "llvm/Support/raw_ostream.h"
33
DeLesley Hutchins3277a612013-10-09 18:30:24 +000034// TODO: Use information from tests in while-loop conditional.
DeLesley Hutchinsfc368252013-09-03 20:11:38 +000035// TODO: Add notes about the actual and expected state for
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000036// TODO: Correctly identify unreachable blocks when chaining boolean operators.
DeLesley Hutchins210791a2013-10-04 21:28:06 +000037// TODO: Adjust the parser and AttributesList class to support lists of
38// identifiers.
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000039// TODO: Warn about unreachable code.
40// TODO: Switch to using a bitmap to track unreachable blocks.
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000041// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
42// if (valid) ...; (Deferred)
DeLesley Hutchins48a31762013-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 Hutchins48a31762013-08-12 21:20:55 +000047
48using namespace clang;
49using namespace consumed;
50
51// Key method definition
52ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
53
DeLesley Hutchins65013202013-10-17 18:19:31 +000054static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
55 // Find the source location of the first statement in the block, if the block
56 // is not empty.
57 for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
58 BI != BE; ++BI) {
59 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
60 return CS->getStmt()->getLocStart();
61 }
62
63 // Block is empty.
64 // If we have one successor, return the first statement in that block
65 if (Block->succ_size() == 1 && *Block->succ_begin())
66 return getFirstStmtLoc(*Block->succ_begin());
67
68 return SourceLocation();
69}
70
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +000071static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +000072 // Find the source location of the last statement in the block, if the block
73 // is not empty.
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +000074 if (const Stmt *StmtNode = Block->getTerminator()) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +000075 return StmtNode->getLocStart();
76 } else {
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +000077 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
78 BE = Block->rend(); BI != BE; ++BI) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +000079 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
80 return CS->getStmt()->getLocStart();
81 }
82 }
DeLesley Hutchins65013202013-10-17 18:19:31 +000083
84 // If we have one successor, return the first statement in that block
85 SourceLocation Loc;
86 if (Block->succ_size() == 1 && *Block->succ_begin())
87 Loc = getFirstStmtLoc(*Block->succ_begin());
88 if (Loc.isValid())
89 return Loc;
DeLesley Hutchins3277a612013-10-09 18:30:24 +000090
DeLesley Hutchins65013202013-10-17 18:19:31 +000091 // If we have one predecessor, return the last statement in that block
92 if (Block->pred_size() == 1 && *Block->pred_begin())
93 return getLastStmtLoc(*Block->pred_begin());
94
95 return Loc;
DeLesley Hutchins3277a612013-10-09 18:30:24 +000096}
97
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000098static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
99 switch (State) {
100 case CS_Unconsumed:
101 return CS_Consumed;
102 case CS_Consumed:
103 return CS_Unconsumed;
104 case CS_None:
105 return CS_None;
106 case CS_Unknown:
107 return CS_Unknown;
108 }
109 llvm_unreachable("invalid enum");
110}
111
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000112static bool isCallableInState(const CallableWhenAttr *CWAttr,
113 ConsumedState State) {
114
115 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
116 E = CWAttr->callableState_end();
117
118 for (; I != E; ++I) {
119
120 ConsumedState MappedAttrState = CS_None;
121
122 switch (*I) {
123 case CallableWhenAttr::Unknown:
124 MappedAttrState = CS_Unknown;
125 break;
126
127 case CallableWhenAttr::Unconsumed:
128 MappedAttrState = CS_Unconsumed;
129 break;
130
131 case CallableWhenAttr::Consumed:
132 MappedAttrState = CS_Consumed;
133 break;
134 }
135
136 if (MappedAttrState == State)
137 return true;
138 }
139
140 return false;
141}
142
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000143static bool isConsumableType(const QualType &QT) {
144 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
145 return RD->hasAttr<ConsumableAttr>();
146 else
147 return false;
148}
149
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000150static bool isKnownState(ConsumedState State) {
151 switch (State) {
152 case CS_Unconsumed:
153 case CS_Consumed:
154 return true;
155 case CS_None:
156 case CS_Unknown:
157 return false;
158 }
Aaron Ballmana21f4b82013-08-29 20:36:09 +0000159 llvm_unreachable("invalid enum");
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000160}
161
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000162static bool isTestingFunction(const FunctionDecl *FunDecl) {
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000163 return FunDecl->hasAttr<TestsTypestateAttr>();
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000164}
165
David Blaikie16f76d22013-09-06 01:28:43 +0000166static ConsumedState mapConsumableAttrState(const QualType QT) {
167 assert(isConsumableType(QT));
168
169 const ConsumableAttr *CAttr =
170 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
171
172 switch (CAttr->getDefaultState()) {
173 case ConsumableAttr::Unknown:
174 return CS_Unknown;
175 case ConsumableAttr::Unconsumed:
176 return CS_Unconsumed;
177 case ConsumableAttr::Consumed:
178 return CS_Consumed;
179 }
180 llvm_unreachable("invalid enum");
181}
182
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000183static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
184 switch (STAttr->getNewState()) {
185 case SetTypestateAttr::Unknown:
186 return CS_Unknown;
187 case SetTypestateAttr::Unconsumed:
188 return CS_Unconsumed;
189 case SetTypestateAttr::Consumed:
190 return CS_Consumed;
191 }
192 llvm_unreachable("invalid_enum");
193}
194
Eric Christopherde156242013-09-03 20:43:00 +0000195static ConsumedState
196mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000197 switch (RTSAttr->getState()) {
198 case ReturnTypestateAttr::Unknown:
199 return CS_Unknown;
200 case ReturnTypestateAttr::Unconsumed:
201 return CS_Unconsumed;
202 case ReturnTypestateAttr::Consumed:
203 return CS_Consumed;
204 }
Eric Christopherde156242013-09-03 20:43:00 +0000205 llvm_unreachable("invalid enum");
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000206}
207
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000208static StringRef stateToString(ConsumedState State) {
209 switch (State) {
210 case consumed::CS_None:
211 return "none";
212
213 case consumed::CS_Unknown:
214 return "unknown";
215
216 case consumed::CS_Unconsumed:
217 return "unconsumed";
218
219 case consumed::CS_Consumed:
220 return "consumed";
221 }
Reid Kleckner6454d0a2013-08-13 00:11:59 +0000222 llvm_unreachable("invalid enum");
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000223}
224
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000225static ConsumedState testsFor(const FunctionDecl *FunDecl) {
226 assert(isTestingFunction(FunDecl));
227 switch (FunDecl->getAttr<TestsTypestateAttr>()->getTestState()) {
228 case TestsTypestateAttr::Unconsumed:
229 return CS_Unconsumed;
230 case TestsTypestateAttr::Consumed:
231 return CS_Consumed;
232 }
233 llvm_unreachable("invalid enum");
234}
235
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000236namespace {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000237struct VarTestResult {
238 const VarDecl *Var;
239 ConsumedState TestsFor;
240};
241} // end anonymous::VarTestResult
242
243namespace clang {
244namespace consumed {
245
246enum EffectiveOp {
247 EO_And,
248 EO_Or
249};
250
251class PropagationInfo {
252 enum {
253 IT_None,
254 IT_State,
255 IT_Test,
256 IT_BinTest,
257 IT_Var
258 } InfoType;
Eric Christopherf8a1baa2013-08-29 18:00:58 +0000259
260 struct BinTestTy {
261 const BinaryOperator *Source;
262 EffectiveOp EOp;
263 VarTestResult LTest;
264 VarTestResult RTest;
265 };
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000266
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000267 union {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000268 ConsumedState State;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000269 VarTestResult Test;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000270 const VarDecl *Var;
Eric Christopherf8a1baa2013-08-29 18:00:58 +0000271 BinTestTy BinTest;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000272 };
273
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000274 QualType TempType;
275
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000276public:
277 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000278
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000279 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
280 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
281 : InfoType(IT_Test) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000282
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000283 Test.Var = Var;
284 Test.TestsFor = TestsFor;
285 }
286
287 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
288 const VarTestResult &LTest, const VarTestResult &RTest)
289 : InfoType(IT_BinTest) {
290
291 BinTest.Source = Source;
292 BinTest.EOp = EOp;
293 BinTest.LTest = LTest;
294 BinTest.RTest = RTest;
295 }
296
297 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
298 const VarDecl *LVar, ConsumedState LTestsFor,
299 const VarDecl *RVar, ConsumedState RTestsFor)
300 : InfoType(IT_BinTest) {
301
302 BinTest.Source = Source;
303 BinTest.EOp = EOp;
304 BinTest.LTest.Var = LVar;
305 BinTest.LTest.TestsFor = LTestsFor;
306 BinTest.RTest.Var = RVar;
307 BinTest.RTest.TestsFor = RTestsFor;
308 }
309
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000310 PropagationInfo(ConsumedState State, QualType TempType)
311 : InfoType(IT_State), State(State), TempType(TempType) {}
312
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000313 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
314
315 const ConsumedState & getState() const {
316 assert(InfoType == IT_State);
317 return State;
318 }
319
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000320 const QualType & getTempType() const {
321 assert(InfoType == IT_State);
322 return TempType;
323 }
324
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000325 const VarTestResult & getTest() const {
326 assert(InfoType == IT_Test);
327 return Test;
328 }
329
330 const VarTestResult & getLTest() const {
331 assert(InfoType == IT_BinTest);
332 return BinTest.LTest;
333 }
334
335 const VarTestResult & getRTest() const {
336 assert(InfoType == IT_BinTest);
337 return BinTest.RTest;
338 }
339
340 const VarDecl * getVar() const {
341 assert(InfoType == IT_Var);
342 return Var;
343 }
344
345 EffectiveOp testEffectiveOp() const {
346 assert(InfoType == IT_BinTest);
347 return BinTest.EOp;
348 }
349
350 const BinaryOperator * testSourceNode() const {
351 assert(InfoType == IT_BinTest);
352 return BinTest.Source;
353 }
354
355 bool isValid() const { return InfoType != IT_None; }
356 bool isState() const { return InfoType == IT_State; }
357 bool isTest() const { return InfoType == IT_Test; }
358 bool isBinTest() const { return InfoType == IT_BinTest; }
359 bool isVar() const { return InfoType == IT_Var; }
360
361 PropagationInfo invertTest() const {
362 assert(InfoType == IT_Test || InfoType == IT_BinTest);
363
364 if (InfoType == IT_Test) {
365 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
366
367 } else if (InfoType == IT_BinTest) {
368 return PropagationInfo(BinTest.Source,
369 BinTest.EOp == EO_And ? EO_Or : EO_And,
370 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
371 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
372 } else {
373 return PropagationInfo();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000374 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000375 }
376};
377
378class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000379
380 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
381 typedef std::pair<const Stmt *, PropagationInfo> PairType;
382 typedef MapType::iterator InfoEntry;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000383 typedef MapType::const_iterator ConstInfoEntry;
384
Reid Klecknere846dea2013-08-12 23:49:39 +0000385 AnalysisDeclContext &AC;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000386 ConsumedAnalyzer &Analyzer;
387 ConsumedStateMap *StateMap;
388 MapType PropagationMap;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000389 void forwardInfo(const Stmt *From, const Stmt *To);
390 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000391 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
392 QualType ReturnType);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000393
394public:
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000395 void checkCallability(const PropagationInfo &PInfo,
396 const FunctionDecl *FunDecl,
397 SourceLocation BlameLoc);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000398
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000399 void Visit(const Stmt *StmtNode);
400
401 void VisitBinaryOperator(const BinaryOperator *BinOp);
402 void VisitCallExpr(const CallExpr *Call);
403 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000404 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000405 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
406 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
407 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
408 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
409 void VisitDeclStmt(const DeclStmt *DelcS);
410 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
411 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000412 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000413 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000414 void VisitUnaryOperator(const UnaryOperator *UOp);
415 void VisitVarDecl(const VarDecl *Var);
Reid Klecknere846dea2013-08-12 23:49:39 +0000416
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000417 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
418 ConsumedStateMap *StateMap)
419 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000420
421 PropagationInfo getInfo(const Stmt *StmtNode) const {
422 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
423
424 if (Entry != PropagationMap.end())
425 return Entry->second;
426 else
427 return PropagationInfo();
428 }
429
430 void reset(ConsumedStateMap *NewStateMap) {
431 StateMap = NewStateMap;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000432 }
433};
434
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000435void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000436 const FunctionDecl *FunDecl,
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000437 SourceLocation BlameLoc) {
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000438
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000439 if (!FunDecl->hasAttr<CallableWhenAttr>())
440 return;
441
442 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000443
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000444 if (PInfo.isVar()) {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000445 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000446 ConsumedState VarState = StateMap->getState(Var);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000447
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000448 assert(VarState != CS_None && "Invalid state");
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000449
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000450 if (isCallableInState(CWAttr, VarState))
451 return;
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000452
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000453 Analyzer.WarningsHandler.warnUseInInvalidState(
454 FunDecl->getNameAsString(), Var->getNameAsString(),
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000455 stateToString(VarState), BlameLoc);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000456
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000457 } else if (PInfo.isState()) {
458
459 assert(PInfo.getState() != CS_None && "Invalid state");
460
461 if (isCallableInState(CWAttr, PInfo.getState()))
462 return;
463
464 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000465 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000466 }
467}
468
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000469void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
470 InfoEntry Entry = PropagationMap.find(From);
471
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000472 if (Entry != PropagationMap.end())
473 PropagationMap.insert(PairType(To, Entry->second));
474}
475
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000476bool ConsumedStmtVisitor::isLikeMoveAssignment(
477 const CXXMethodDecl *MethodDecl) {
478
479 return MethodDecl->isMoveAssignmentOperator() ||
480 (MethodDecl->getOverloadedOperator() == OO_Equal &&
481 MethodDecl->getNumParams() == 1 &&
482 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
483}
484
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000485void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
486 const FunctionDecl *Fun,
487 QualType ReturnType) {
488 if (isConsumableType(ReturnType)) {
489
490 ConsumedState ReturnState;
491
492 if (Fun->hasAttr<ReturnTypestateAttr>())
493 ReturnState = mapReturnTypestateAttrState(
494 Fun->getAttr<ReturnTypestateAttr>());
495 else
David Blaikie16f76d22013-09-06 01:28:43 +0000496 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000497
498 PropagationMap.insert(PairType(Call,
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000499 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000500 }
501}
502
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000503void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
504
505 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
506
507 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
508 CE = StmtNode->child_end(); CI != CE; ++CI) {
509
510 PropagationMap.erase(*CI);
511 }
512}
513
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000514void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
515 switch (BinOp->getOpcode()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000516 case BO_LAnd:
517 case BO_LOr : {
518 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
519 REntry = PropagationMap.find(BinOp->getRHS());
520
521 VarTestResult LTest, RTest;
522
523 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
524 LTest = LEntry->second.getTest();
525
526 } else {
527 LTest.Var = NULL;
528 LTest.TestsFor = CS_None;
529 }
530
531 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
532 RTest = REntry->second.getTest();
533
534 } else {
535 RTest.Var = NULL;
536 RTest.TestsFor = CS_None;
537 }
538
539 if (!(LTest.Var == NULL && RTest.Var == NULL))
540 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
541 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
542
543 break;
544 }
545
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000546 case BO_PtrMemD:
547 case BO_PtrMemI:
548 forwardInfo(BinOp->getLHS(), BinOp);
549 break;
550
551 default:
552 break;
553 }
554}
555
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000556void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
557 if (const FunctionDecl *FunDecl =
558 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
559
560 // Special case for the std::move function.
561 // TODO: Make this more specific. (Deferred)
562 if (FunDecl->getNameAsString() == "move") {
563 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
564
565 if (Entry != PropagationMap.end()) {
566 PropagationMap.insert(PairType(Call, Entry->second));
567 }
568
569 return;
570 }
571
572 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
573
574 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
575 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
576
577 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
578
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000579 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000580 continue;
581 }
582
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000583 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000584
585 if (ParamType->isRValueReferenceType() ||
586 (ParamType->isLValueReferenceType() &&
587 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
588
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000589 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000590
591 } else if (!(ParamType.isConstQualified() ||
592 ((ParamType->isReferenceType() ||
593 ParamType->isPointerType()) &&
594 ParamType->getPointeeType().isConstQualified()))) {
595
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000596 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000597 }
598 }
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000599
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000600 QualType RetType = FunDecl->getCallResultType();
601 if (RetType->isReferenceType())
602 RetType = RetType->getPointeeType();
603
604 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000605 }
606}
607
608void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000609 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000610}
611
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000612void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
613 const CXXBindTemporaryExpr *Temp) {
614
615 forwardInfo(Temp->getSubExpr(), Temp);
616}
617
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000618void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
619 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Klecknere846dea2013-08-12 23:49:39 +0000620
621 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000622 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
623
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000624 if (isConsumableType(ThisType)) {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000625 if (Constructor->isDefaultConstructor()) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000626
627 PropagationMap.insert(PairType(Call,
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000628 PropagationInfo(consumed::CS_Consumed, ThisType)));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000629
630 } else if (Constructor->isMoveConstructor()) {
631
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000632 PropagationInfo PInfo =
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000633 PropagationMap.find(Call->getArg(0))->second;
634
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000635 if (PInfo.isVar()) {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000636 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000637
638 PropagationMap.insert(PairType(Call,
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000639 PropagationInfo(StateMap->getState(Var), ThisType)));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000640
641 StateMap->setState(Var, consumed::CS_Consumed);
642
643 } else {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000644 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000645 }
646
647 } else if (Constructor->isCopyConstructor()) {
648 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
649
650 if (Entry != PropagationMap.end())
651 PropagationMap.insert(PairType(Call, Entry->second));
652
653 } else {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000654 propagateReturnType(Call, Constructor, ThisType);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000655 }
656 }
657}
658
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000659
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000660void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
661 const CXXMemberCallExpr *Call) {
662
663 VisitCallExpr(Call);
664
665 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
666
667 if (Entry != PropagationMap.end()) {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000668 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000669 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000670
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000671 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000672
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000673 if (PInfo.isVar()) {
674 if (isTestingFunction(MethodDecl))
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000675 PropagationMap.insert(PairType(Call,
676 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000677 else if (MethodDecl->hasAttr<SetTypestateAttr>())
678 StateMap->setState(PInfo.getVar(),
679 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000680 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000681 }
682}
683
684void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
685 const CXXOperatorCallExpr *Call) {
686
687 const FunctionDecl *FunDecl =
688 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
689
690 if (!FunDecl) return;
691
692 if (isa<CXXMethodDecl>(FunDecl) &&
693 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
694
695 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
696 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
697
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000698 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000699
700 if (LEntry != PropagationMap.end() &&
701 REntry != PropagationMap.end()) {
702
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000703 LPInfo = LEntry->second;
704 RPInfo = REntry->second;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000705
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000706 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000707 StateMap->setState(LPInfo.getVar(),
708 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000709
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000710 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000711
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000712 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000713
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000714 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000715 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000716
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000717 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000718
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000719 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000720 PropagationMap.insert(PairType(Call,
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000721 PropagationInfo(StateMap->getState(RPInfo.getVar()),
722 LPInfo.getTempType())));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000723
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000724 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000725
726 } else {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000727 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000728 }
729
730 } else if (LEntry != PropagationMap.end() &&
731 REntry == PropagationMap.end()) {
732
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000733 LPInfo = LEntry->second;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000734
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000735 if (LPInfo.isVar()) {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000736 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000737
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000738 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000739
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000740 } else if (LPInfo.isState()) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000741 PropagationMap.insert(PairType(Call,
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000742 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000743 }
744
745 } else if (LEntry == PropagationMap.end() &&
746 REntry != PropagationMap.end()) {
747
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000748 if (REntry->second.isVar())
749 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000750 }
751
752 } else {
753
754 VisitCallExpr(Call);
755
756 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
757
758 if (Entry != PropagationMap.end()) {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000759 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000760
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000761 checkCallability(PInfo, FunDecl, Call->getExprLoc());
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000762
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000763 if (PInfo.isVar()) {
DeLesley Hutchins7fa60ed2013-08-29 21:17:25 +0000764 if (isTestingFunction(FunDecl))
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000765 PropagationMap.insert(PairType(Call,
766 PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000767 else if (FunDecl->hasAttr<SetTypestateAttr>())
768 StateMap->setState(PInfo.getVar(),
769 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000770 }
771 }
772 }
773}
774
775void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
776 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
777 if (StateMap->getState(Var) != consumed::CS_None)
778 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
779}
780
781void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
782 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
783 DE = DeclS->decl_end(); DI != DE; ++DI) {
784
785 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
786 }
787
788 if (DeclS->isSingleDecl())
789 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
790 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
791}
792
793void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
794 const MaterializeTemporaryExpr *Temp) {
795
796 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
797
798 if (Entry != PropagationMap.end())
799 PropagationMap.insert(PairType(Temp, Entry->second));
800}
801
802void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
803 forwardInfo(MExpr->getBase(), MExpr);
804}
805
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000806
807void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikie16f76d22013-09-06 01:28:43 +0000808 QualType ParamType = Param->getType();
809 ConsumedState ParamState = consumed::CS_None;
810
811 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
812 isConsumableType(ParamType))
813 ParamState = mapConsumableAttrState(ParamType);
814 else if (ParamType->isReferenceType() &&
815 isConsumableType(ParamType->getPointeeType()))
816 ParamState = consumed::CS_Unknown;
817
818 if (ParamState)
819 StateMap->setState(Param, ParamState);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000820}
821
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000822void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
823 if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) {
824 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
825
826 if (Entry != PropagationMap.end()) {
827 assert(Entry->second.isState() || Entry->second.isVar());
828
829 ConsumedState RetState = Entry->second.isState() ?
830 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
831
832 if (RetState != ExpectedState)
833 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
834 Ret->getReturnLoc(), stateToString(ExpectedState),
835 stateToString(RetState));
836 }
837 }
838}
839
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000840void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000841 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
842 if (Entry == PropagationMap.end()) return;
843
844 switch (UOp->getOpcode()) {
845 case UO_AddrOf:
846 PropagationMap.insert(PairType(UOp, Entry->second));
847 break;
848
849 case UO_LNot:
850 if (Entry->second.isTest() || Entry->second.isBinTest())
851 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
852 break;
853
854 default:
855 break;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000856 }
857}
858
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000859// TODO: See if I need to check for reference types here.
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000860void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000861 if (isConsumableType(Var->getType())) {
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000862 if (Var->hasInit()) {
863 PropagationInfo PInfo =
864 PropagationMap.find(Var->getInit())->second;
865
866 StateMap->setState(Var, PInfo.isVar() ?
867 StateMap->getState(PInfo.getVar()) : PInfo.getState());
868
869 } else {
870 StateMap->setState(Var, consumed::CS_Unknown);
871 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000872 }
873}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000874}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000875
876namespace clang {
877namespace consumed {
878
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000879void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
880 ConsumedStateMap *ThenStates,
881 ConsumedStateMap *ElseStates) {
882
883 ConsumedState VarState = ThenStates->getState(Test.Var);
884
885 if (VarState == CS_Unknown) {
886 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000887 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000888
889 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
890 ThenStates->markUnreachable();
891
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000892 } else if (VarState == Test.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000893 ElseStates->markUnreachable();
894 }
895}
896
897void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
898 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
899
900 const VarTestResult &LTest = PInfo.getLTest(),
901 &RTest = PInfo.getRTest();
902
903 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
904 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
905
906 if (LTest.Var) {
907 if (PInfo.testEffectiveOp() == EO_And) {
908 if (LState == CS_Unknown) {
909 ThenStates->setState(LTest.Var, LTest.TestsFor);
910
911 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
912 ThenStates->markUnreachable();
913
914 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000915 if (RState == RTest.TestsFor)
916 ElseStates->markUnreachable();
917 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000918 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000919 }
920
921 } else {
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000922 if (LState == CS_Unknown) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000923 ElseStates->setState(LTest.Var,
924 invertConsumedUnconsumed(LTest.TestsFor));
925
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000926 } else if (LState == LTest.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000927 ElseStates->markUnreachable();
928
929 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
930 isKnownState(RState)) {
931
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000932 if (RState == RTest.TestsFor)
933 ElseStates->markUnreachable();
934 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000935 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000936 }
937 }
938 }
939
940 if (RTest.Var) {
941 if (PInfo.testEffectiveOp() == EO_And) {
942 if (RState == CS_Unknown)
943 ThenStates->setState(RTest.Var, RTest.TestsFor);
944 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
945 ThenStates->markUnreachable();
946
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000947 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000948 if (RState == CS_Unknown)
949 ElseStates->setState(RTest.Var,
950 invertConsumedUnconsumed(RTest.TestsFor));
951 else if (RState == RTest.TestsFor)
952 ElseStates->markUnreachable();
953 }
954 }
955}
956
DeLesley Hutchins3277a612013-10-09 18:30:24 +0000957bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
958 const CFGBlock *TargetBlock) {
959
960 assert(CurrBlock && "Block pointer must not be NULL");
961 assert(TargetBlock && "TargetBlock pointer must not be NULL");
962
963 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
964 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
965 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
966 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
967 return false;
968 }
969 return true;
970}
971
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000972void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
973 ConsumedStateMap *StateMap,
974 bool &AlreadyOwned) {
975
DeLesley Hutchins3277a612013-10-09 18:30:24 +0000976 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000977
978 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
979
980 if (Entry) {
981 Entry->intersect(StateMap);
982
983 } else if (AlreadyOwned) {
984 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
985
986 } else {
987 StateMapsArray[Block->getBlockID()] = StateMap;
988 AlreadyOwned = true;
989 }
990}
991
992void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
993 ConsumedStateMap *StateMap) {
994
DeLesley Hutchins3277a612013-10-09 18:30:24 +0000995 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000996
997 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
998
999 if (Entry) {
1000 Entry->intersect(StateMap);
1001 delete StateMap;
1002
1003 } else {
1004 StateMapsArray[Block->getBlockID()] = StateMap;
1005 }
1006}
1007
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001008ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1009 assert(Block && "Block pointer must not be NULL");
1010 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1011
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001012 return StateMapsArray[Block->getBlockID()];
1013}
1014
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001015void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1016 unsigned int BlockID = Block->getBlockID();
1017 delete StateMapsArray[BlockID];
1018 StateMapsArray[BlockID] = NULL;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001019}
1020
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001021ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1022 assert(Block && "Block pointer must not be NULL");
1023
1024 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1025 if (isBackEdgeTarget(Block)) {
1026 return new ConsumedStateMap(*StateMap);
1027 } else {
1028 StateMapsArray[Block->getBlockID()] = NULL;
1029 return StateMap;
1030 }
1031}
1032
1033bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1034 assert(From && "From block must not be NULL");
1035 assert(To && "From block must not be NULL");
1036
1037 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1038}
1039
1040bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1041 assert(Block != NULL && "Block pointer must not be NULL");
1042
1043 // Anything with less than two predecessors can't be the target of a back
1044 // edge.
1045 if (Block->pred_size() < 2)
1046 return false;
1047
1048 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1049 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1050 PE = Block->pred_end(); PI != PE; ++PI) {
1051 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1052 return true;
1053 }
1054 return false;
1055}
1056
1057ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001058 MapType::const_iterator Entry = Map.find(Var);
1059
1060 if (Entry != Map.end()) {
1061 return Entry->second;
1062
1063 } else {
1064 return CS_None;
1065 }
1066}
1067
1068void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1069 ConsumedState LocalState;
1070
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001071 if (this->From && this->From == Other->From && !Other->Reachable) {
1072 this->markUnreachable();
1073 return;
1074 }
1075
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001076 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1077 DMI != DME; ++DMI) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001078
1079 LocalState = this->getState(DMI->first);
1080
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001081 if (LocalState == CS_None)
1082 continue;
1083
1084 if (LocalState != DMI->second)
1085 Map[DMI->first] = CS_Unknown;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001086 }
1087}
1088
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001089void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1090 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1091 ConsumedWarningsHandlerBase &WarningsHandler) {
1092
1093 ConsumedState LocalState;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001094 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001095
1096 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1097 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1098
1099 LocalState = this->getState(DMI->first);
1100
1101 if (LocalState == CS_None)
1102 continue;
1103
1104 if (LocalState != DMI->second) {
1105 Map[DMI->first] = CS_Unknown;
1106 WarningsHandler.warnLoopStateMismatch(
1107 BlameLoc, DMI->first->getNameAsString());
1108 }
1109 }
1110}
1111
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001112void ConsumedStateMap::markUnreachable() {
1113 this->Reachable = false;
1114 Map.clear();
1115}
1116
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001117void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1118 Map[Var] = State;
1119}
1120
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001121void ConsumedStateMap::remove(const VarDecl *Var) {
1122 Map.erase(Var);
1123}
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001124
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001125bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1126 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1127 DMI != DME; ++DMI) {
1128
1129 if (this->getState(DMI->first) != DMI->second)
1130 return true;
1131 }
1132
1133 return false;
1134}
1135
David Blaikie16f76d22013-09-06 01:28:43 +00001136void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1137 const FunctionDecl *D) {
1138 QualType ReturnType;
1139 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1140 ASTContext &CurrContext = AC.getASTContext();
1141 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1142 } else
1143 ReturnType = D->getCallResultType();
1144
1145 if (D->hasAttr<ReturnTypestateAttr>()) {
1146 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1147
1148 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1149 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1150 // FIXME: This should be removed when template instantiation propagates
1151 // attributes at template specialization definition, not
1152 // declaration. When it is removed the test needs to be enabled
1153 // in SemaDeclAttr.cpp.
1154 WarningsHandler.warnReturnTypestateForUnconsumableType(
1155 RTSAttr->getLocation(), ReturnType.getAsString());
1156 ExpectedReturnState = CS_None;
1157 } else
1158 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1159 } else if (isConsumableType(ReturnType))
1160 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1161 else
1162 ExpectedReturnState = CS_None;
1163}
1164
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001165bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1166 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001167
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001168 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1169 PropagationInfo PInfo;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001170
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001171 if (const IfStmt *IfNode =
1172 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001173
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001174 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001175
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001176 PInfo = Visitor.getInfo(Cond);
1177 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1178 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1179
1180 if (PInfo.isTest()) {
1181 CurrStates->setSource(Cond);
1182 FalseStates->setSource(Cond);
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001183 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001184
1185 } else if (PInfo.isBinTest()) {
1186 CurrStates->setSource(PInfo.testSourceNode());
1187 FalseStates->setSource(PInfo.testSourceNode());
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001188 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001189
1190 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001191 delete FalseStates;
1192 return false;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001193 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001194
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001195 } else if (const BinaryOperator *BinOp =
1196 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1197
1198 PInfo = Visitor.getInfo(BinOp->getLHS());
1199 if (!PInfo.isTest()) {
1200 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1201 PInfo = Visitor.getInfo(BinOp->getRHS());
1202
1203 if (!PInfo.isTest()) {
1204 delete FalseStates;
1205 return false;
1206 }
1207
1208 } else {
1209 delete FalseStates;
1210 return false;
1211 }
1212 }
1213
1214 CurrStates->setSource(BinOp);
1215 FalseStates->setSource(BinOp);
1216
1217 const VarTestResult &Test = PInfo.getTest();
1218 ConsumedState VarState = CurrStates->getState(Test.Var);
1219
1220 if (BinOp->getOpcode() == BO_LAnd) {
1221 if (VarState == CS_Unknown)
1222 CurrStates->setState(Test.Var, Test.TestsFor);
1223 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1224 CurrStates->markUnreachable();
1225
1226 } else if (BinOp->getOpcode() == BO_LOr) {
1227 if (VarState == CS_Unknown)
1228 FalseStates->setState(Test.Var,
1229 invertConsumedUnconsumed(Test.TestsFor));
1230 else if (VarState == Test.TestsFor)
1231 FalseStates->markUnreachable();
1232 }
1233
1234 } else {
1235 delete FalseStates;
1236 return false;
1237 }
1238
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001239 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1240
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001241 if (*SI)
1242 BlockInfo.addInfo(*SI, CurrStates);
1243 else
1244 delete CurrStates;
1245
1246 if (*++SI)
1247 BlockInfo.addInfo(*SI, FalseStates);
1248 else
1249 delete FalseStates;
1250
1251 CurrStates = NULL;
1252 return true;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001253}
1254
1255void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1256 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001257 if (!D)
1258 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001259
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001260 CFG *CFGraph = AC.getCFG();
1261 if (!CFGraph)
1262 return;
DeLesley Hutchins65013202013-10-17 18:19:31 +00001263
David Blaikie16f76d22013-09-06 01:28:43 +00001264 determineExpectedReturnState(AC, D);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001265
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001266 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001267 // AC.getCFG()->viewCFG(LangOptions());
1268
1269 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001270
1271 CurrStates = new ConsumedStateMap();
DeLesley Hutchinsb570c132013-08-29 22:36:05 +00001272 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1273
1274 // Add all trackable parameters to the state map.
1275 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1276 PE = D->param_end(); PI != PE; ++PI) {
1277 Visitor.VisitParmVarDecl(*PI);
1278 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001279
1280 // Visit all of the function's basic blocks.
1281 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1282 E = SortedGraph->end(); I != E; ++I) {
1283
1284 const CFGBlock *CurrBlock = *I;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001285
1286 if (CurrStates == NULL)
1287 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001288
1289 if (!CurrStates) {
1290 continue;
1291
1292 } else if (!CurrStates->isReachable()) {
1293 delete CurrStates;
1294 CurrStates = NULL;
1295 continue;
1296 }
1297
1298 Visitor.reset(CurrStates);
1299
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001300 // Visit all of the basic block's statements.
1301 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1302 BE = CurrBlock->end(); BI != BE; ++BI) {
1303
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001304 switch (BI->getKind()) {
1305 case CFGElement::Statement:
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001306 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001307 break;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001308
1309 case CFGElement::TemporaryDtor: {
1310 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1311 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1312 PropagationInfo PInfo = Visitor.getInfo(BTE);
1313
1314 if (PInfo.isValid())
1315 Visitor.checkCallability(PInfo,
1316 DTor.getDestructorDecl(AC.getASTContext()),
1317 BTE->getExprLoc());
1318 break;
1319 }
1320
1321 case CFGElement::AutomaticObjectDtor: {
1322 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1323
1324 const VarDecl *Var = DTor.getVarDecl();
1325 ConsumedState VarState = CurrStates->getState(Var);
1326
1327 if (VarState != CS_None) {
1328 PropagationInfo PInfo(Var);
1329
1330 Visitor.checkCallability(PInfo,
1331 DTor.getDestructorDecl(AC.getASTContext()),
1332 getLastStmtLoc(CurrBlock));
1333
1334 CurrStates->remove(Var);
1335 }
1336 break;
1337 }
1338
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001339 default:
1340 break;
1341 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001342 }
1343
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001344 // TODO: Handle other forms of branching with precision, including while-
1345 // and for-loops. (Deferred)
1346 if (!splitState(CurrBlock, Visitor)) {
1347 CurrStates->setSource(NULL);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001348
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001349 if (CurrBlock->succ_size() > 1 ||
1350 (CurrBlock->succ_size() == 1 &&
1351 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001352
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001353 bool OwnershipTaken = false;
1354
1355 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1356 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1357
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001358 if (*SI == NULL) continue;
1359
1360 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1361 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1362 CurrStates,
1363 WarningsHandler);
1364
1365 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1366 BlockInfo.discardInfo(*SI);
1367 } else {
1368 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1369 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001370 }
1371
1372 if (!OwnershipTaken)
1373 delete CurrStates;
1374
1375 CurrStates = NULL;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001376 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001377 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001378 } // End of block iterator.
1379
1380 // Delete the last existing state map.
1381 delete CurrStates;
1382
1383 WarningsHandler.emitDiagnostics();
1384}
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001385}} // end namespace clang::consumed