blob: c51c02335c5f92cdf6bb81d6ec2154d41a5b4936 [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) {
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000140 return FunDecl->hasAttr<TestsTypestateAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000141}
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
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000160static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
161 switch (STAttr->getNewState()) {
162 case SetTypestateAttr::Unknown:
163 return CS_Unknown;
164 case SetTypestateAttr::Unconsumed:
165 return CS_Unconsumed;
166 case SetTypestateAttr::Consumed:
167 return CS_Consumed;
168 }
169 llvm_unreachable("invalid_enum");
170}
171
Eric Christophere988dc42013-09-03 20:43:00 +0000172static ConsumedState
173mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000174 switch (RTSAttr->getState()) {
175 case ReturnTypestateAttr::Unknown:
176 return CS_Unknown;
177 case ReturnTypestateAttr::Unconsumed:
178 return CS_Unconsumed;
179 case ReturnTypestateAttr::Consumed:
180 return CS_Consumed;
181 }
Eric Christophere988dc42013-09-03 20:43:00 +0000182 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000183}
184
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000185static StringRef stateToString(ConsumedState State) {
186 switch (State) {
187 case consumed::CS_None:
188 return "none";
189
190 case consumed::CS_Unknown:
191 return "unknown";
192
193 case consumed::CS_Unconsumed:
194 return "unconsumed";
195
196 case consumed::CS_Consumed:
197 return "consumed";
198 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000199 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000200}
201
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000202static ConsumedState testsFor(const FunctionDecl *FunDecl) {
203 assert(isTestingFunction(FunDecl));
204 switch (FunDecl->getAttr<TestsTypestateAttr>()->getTestState()) {
205 case TestsTypestateAttr::Unconsumed:
206 return CS_Unconsumed;
207 case TestsTypestateAttr::Consumed:
208 return CS_Consumed;
209 }
210 llvm_unreachable("invalid enum");
211}
212
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000213namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000214struct VarTestResult {
215 const VarDecl *Var;
216 ConsumedState TestsFor;
217};
218} // end anonymous::VarTestResult
219
220namespace clang {
221namespace consumed {
222
223enum EffectiveOp {
224 EO_And,
225 EO_Or
226};
227
228class PropagationInfo {
229 enum {
230 IT_None,
231 IT_State,
232 IT_Test,
233 IT_BinTest,
234 IT_Var
235 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000236
237 struct BinTestTy {
238 const BinaryOperator *Source;
239 EffectiveOp EOp;
240 VarTestResult LTest;
241 VarTestResult RTest;
242 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000243
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000244 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000245 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000246 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000247 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000248 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000249 };
250
DeLesley Hutchins66540852013-10-04 21:28:06 +0000251 QualType TempType;
252
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000253public:
254 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000255
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000256 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
257 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
258 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000259
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000260 Test.Var = Var;
261 Test.TestsFor = TestsFor;
262 }
263
264 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
265 const VarTestResult &LTest, const VarTestResult &RTest)
266 : InfoType(IT_BinTest) {
267
268 BinTest.Source = Source;
269 BinTest.EOp = EOp;
270 BinTest.LTest = LTest;
271 BinTest.RTest = RTest;
272 }
273
274 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
275 const VarDecl *LVar, ConsumedState LTestsFor,
276 const VarDecl *RVar, ConsumedState RTestsFor)
277 : InfoType(IT_BinTest) {
278
279 BinTest.Source = Source;
280 BinTest.EOp = EOp;
281 BinTest.LTest.Var = LVar;
282 BinTest.LTest.TestsFor = LTestsFor;
283 BinTest.RTest.Var = RVar;
284 BinTest.RTest.TestsFor = RTestsFor;
285 }
286
DeLesley Hutchins66540852013-10-04 21:28:06 +0000287 PropagationInfo(ConsumedState State, QualType TempType)
288 : InfoType(IT_State), State(State), TempType(TempType) {}
289
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000290 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
291
292 const ConsumedState & getState() const {
293 assert(InfoType == IT_State);
294 return State;
295 }
296
DeLesley Hutchins66540852013-10-04 21:28:06 +0000297 const QualType & getTempType() const {
298 assert(InfoType == IT_State);
299 return TempType;
300 }
301
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000302 const VarTestResult & getTest() const {
303 assert(InfoType == IT_Test);
304 return Test;
305 }
306
307 const VarTestResult & getLTest() const {
308 assert(InfoType == IT_BinTest);
309 return BinTest.LTest;
310 }
311
312 const VarTestResult & getRTest() const {
313 assert(InfoType == IT_BinTest);
314 return BinTest.RTest;
315 }
316
317 const VarDecl * getVar() const {
318 assert(InfoType == IT_Var);
319 return Var;
320 }
321
322 EffectiveOp testEffectiveOp() const {
323 assert(InfoType == IT_BinTest);
324 return BinTest.EOp;
325 }
326
327 const BinaryOperator * testSourceNode() const {
328 assert(InfoType == IT_BinTest);
329 return BinTest.Source;
330 }
331
332 bool isValid() const { return InfoType != IT_None; }
333 bool isState() const { return InfoType == IT_State; }
334 bool isTest() const { return InfoType == IT_Test; }
335 bool isBinTest() const { return InfoType == IT_BinTest; }
336 bool isVar() const { return InfoType == IT_Var; }
337
338 PropagationInfo invertTest() const {
339 assert(InfoType == IT_Test || InfoType == IT_BinTest);
340
341 if (InfoType == IT_Test) {
342 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
343
344 } else if (InfoType == IT_BinTest) {
345 return PropagationInfo(BinTest.Source,
346 BinTest.EOp == EO_And ? EO_Or : EO_And,
347 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
348 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
349 } else {
350 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000351 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000352 }
353};
354
355class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000356
357 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
358 typedef std::pair<const Stmt *, PropagationInfo> PairType;
359 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000360 typedef MapType::const_iterator ConstInfoEntry;
361
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000362 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000363 ConsumedAnalyzer &Analyzer;
364 ConsumedStateMap *StateMap;
365 MapType PropagationMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000366 void forwardInfo(const Stmt *From, const Stmt *To);
367 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000368 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
369 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000370
371public:
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000372 void checkCallability(const PropagationInfo &PInfo,
373 const FunctionDecl *FunDecl,
374 SourceLocation BlameLoc);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000375
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000376 void Visit(const Stmt *StmtNode);
377
378 void VisitBinaryOperator(const BinaryOperator *BinOp);
379 void VisitCallExpr(const CallExpr *Call);
380 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000381 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000382 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
383 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
384 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
385 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
386 void VisitDeclStmt(const DeclStmt *DelcS);
387 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
388 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000389 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000390 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000391 void VisitUnaryOperator(const UnaryOperator *UOp);
392 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000393
DeLesley Hutchins42525982013-08-29 22:36:05 +0000394 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
395 ConsumedStateMap *StateMap)
396 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000397
398 PropagationInfo getInfo(const Stmt *StmtNode) const {
399 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
400
401 if (Entry != PropagationMap.end())
402 return Entry->second;
403 else
404 return PropagationInfo();
405 }
406
407 void reset(ConsumedStateMap *NewStateMap) {
408 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000409 }
410};
411
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000412void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000413 const FunctionDecl *FunDecl,
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000414 SourceLocation BlameLoc) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000415
DeLesley Hutchins66540852013-10-04 21:28:06 +0000416 if (!FunDecl->hasAttr<CallableWhenAttr>())
417 return;
418
419 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000420
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000421 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000422 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins66540852013-10-04 21:28:06 +0000423 ConsumedState VarState = StateMap->getState(Var);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000424
DeLesley Hutchins66540852013-10-04 21:28:06 +0000425 assert(VarState != CS_None && "Invalid state");
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000426
DeLesley Hutchins66540852013-10-04 21:28:06 +0000427 if (isCallableInState(CWAttr, VarState))
428 return;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000429
DeLesley Hutchins66540852013-10-04 21:28:06 +0000430 Analyzer.WarningsHandler.warnUseInInvalidState(
431 FunDecl->getNameAsString(), Var->getNameAsString(),
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000432 stateToString(VarState), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000433
DeLesley Hutchins66540852013-10-04 21:28:06 +0000434 } else if (PInfo.isState()) {
435
436 assert(PInfo.getState() != CS_None && "Invalid state");
437
438 if (isCallableInState(CWAttr, PInfo.getState()))
439 return;
440
441 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000442 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000443 }
444}
445
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000446void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
447 InfoEntry Entry = PropagationMap.find(From);
448
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000449 if (Entry != PropagationMap.end())
450 PropagationMap.insert(PairType(To, Entry->second));
451}
452
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000453bool ConsumedStmtVisitor::isLikeMoveAssignment(
454 const CXXMethodDecl *MethodDecl) {
455
456 return MethodDecl->isMoveAssignmentOperator() ||
457 (MethodDecl->getOverloadedOperator() == OO_Equal &&
458 MethodDecl->getNumParams() == 1 &&
459 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
460}
461
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000462void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
463 const FunctionDecl *Fun,
464 QualType ReturnType) {
465 if (isConsumableType(ReturnType)) {
466
467 ConsumedState ReturnState;
468
469 if (Fun->hasAttr<ReturnTypestateAttr>())
470 ReturnState = mapReturnTypestateAttrState(
471 Fun->getAttr<ReturnTypestateAttr>());
472 else
David Blaikiea33ab602013-09-06 01:28:43 +0000473 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000474
475 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000476 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000477 }
478}
479
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000480void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
481
482 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
483
484 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
485 CE = StmtNode->child_end(); CI != CE; ++CI) {
486
487 PropagationMap.erase(*CI);
488 }
489}
490
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000491void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
492 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000493 case BO_LAnd:
494 case BO_LOr : {
495 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
496 REntry = PropagationMap.find(BinOp->getRHS());
497
498 VarTestResult LTest, RTest;
499
500 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
501 LTest = LEntry->second.getTest();
502
503 } else {
504 LTest.Var = NULL;
505 LTest.TestsFor = CS_None;
506 }
507
508 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
509 RTest = REntry->second.getTest();
510
511 } else {
512 RTest.Var = NULL;
513 RTest.TestsFor = CS_None;
514 }
515
516 if (!(LTest.Var == NULL && RTest.Var == NULL))
517 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
518 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
519
520 break;
521 }
522
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000523 case BO_PtrMemD:
524 case BO_PtrMemI:
525 forwardInfo(BinOp->getLHS(), BinOp);
526 break;
527
528 default:
529 break;
530 }
531}
532
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000533void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
534 if (const FunctionDecl *FunDecl =
535 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
536
537 // Special case for the std::move function.
538 // TODO: Make this more specific. (Deferred)
539 if (FunDecl->getNameAsString() == "move") {
540 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
541
542 if (Entry != PropagationMap.end()) {
543 PropagationMap.insert(PairType(Call, Entry->second));
544 }
545
546 return;
547 }
548
549 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
550
551 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
552 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
553
554 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
555
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000556 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000557 continue;
558 }
559
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000560 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000561
562 if (ParamType->isRValueReferenceType() ||
563 (ParamType->isLValueReferenceType() &&
564 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
565
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000566 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000567
568 } else if (!(ParamType.isConstQualified() ||
569 ((ParamType->isReferenceType() ||
570 ParamType->isPointerType()) &&
571 ParamType->getPointeeType().isConstQualified()))) {
572
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000573 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000574 }
575 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000576
DeLesley Hutchins66540852013-10-04 21:28:06 +0000577 QualType RetType = FunDecl->getCallResultType();
578 if (RetType->isReferenceType())
579 RetType = RetType->getPointeeType();
580
581 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000582 }
583}
584
585void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000586 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000587}
588
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000589void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
590 const CXXBindTemporaryExpr *Temp) {
591
592 forwardInfo(Temp->getSubExpr(), Temp);
593}
594
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000595void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
596 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000597
598 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000599 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
600
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000601 if (isConsumableType(ThisType)) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000602 if (Constructor->isDefaultConstructor()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000603
604 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000605 PropagationInfo(consumed::CS_Consumed, ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000606
607 } else if (Constructor->isMoveConstructor()) {
608
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000609 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000610 PropagationMap.find(Call->getArg(0))->second;
611
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000612 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000613 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000614
615 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000616 PropagationInfo(StateMap->getState(Var), ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000617
618 StateMap->setState(Var, consumed::CS_Consumed);
619
620 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000621 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000622 }
623
624 } else if (Constructor->isCopyConstructor()) {
625 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
626
627 if (Entry != PropagationMap.end())
628 PropagationMap.insert(PairType(Call, Entry->second));
629
630 } else {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000631 propagateReturnType(Call, Constructor, ThisType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000632 }
633 }
634}
635
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000636
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000637void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
638 const CXXMemberCallExpr *Call) {
639
640 VisitCallExpr(Call);
641
642 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
643
644 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000645 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000646 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000647
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000648 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000649
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000650 if (PInfo.isVar()) {
651 if (isTestingFunction(MethodDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000652 PropagationMap.insert(PairType(Call,
653 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000654 else if (MethodDecl->hasAttr<SetTypestateAttr>())
655 StateMap->setState(PInfo.getVar(),
656 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000657 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000658 }
659}
660
661void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
662 const CXXOperatorCallExpr *Call) {
663
664 const FunctionDecl *FunDecl =
665 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
666
667 if (!FunDecl) return;
668
669 if (isa<CXXMethodDecl>(FunDecl) &&
670 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
671
672 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
673 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
674
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000675 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000676
677 if (LEntry != PropagationMap.end() &&
678 REntry != PropagationMap.end()) {
679
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000680 LPInfo = LEntry->second;
681 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000682
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000683 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000684 StateMap->setState(LPInfo.getVar(),
685 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000686
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000687 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000688
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000689 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000690
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000691 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000692 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000693
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000694 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000695
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000696 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000697 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000698 PropagationInfo(StateMap->getState(RPInfo.getVar()),
699 LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000700
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000701 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000702
703 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000704 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000705 }
706
707 } else if (LEntry != PropagationMap.end() &&
708 REntry == PropagationMap.end()) {
709
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000710 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000711
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000712 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000713 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000714
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000715 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000716
DeLesley Hutchins66540852013-10-04 21:28:06 +0000717 } else if (LPInfo.isState()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000718 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000719 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000720 }
721
722 } else if (LEntry == PropagationMap.end() &&
723 REntry != PropagationMap.end()) {
724
DeLesley Hutchins66540852013-10-04 21:28:06 +0000725 if (REntry->second.isVar())
726 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000727 }
728
729 } else {
730
731 VisitCallExpr(Call);
732
733 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
734
735 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000736 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000737
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000738 checkCallability(PInfo, FunDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000739
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000740 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000741 if (isTestingFunction(FunDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000742 PropagationMap.insert(PairType(Call,
743 PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000744 else if (FunDecl->hasAttr<SetTypestateAttr>())
745 StateMap->setState(PInfo.getVar(),
746 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000747 }
748 }
749 }
750}
751
752void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
753 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
754 if (StateMap->getState(Var) != consumed::CS_None)
755 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
756}
757
758void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
759 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
760 DE = DeclS->decl_end(); DI != DE; ++DI) {
761
762 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
763 }
764
765 if (DeclS->isSingleDecl())
766 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
767 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
768}
769
770void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
771 const MaterializeTemporaryExpr *Temp) {
772
773 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
774
775 if (Entry != PropagationMap.end())
776 PropagationMap.insert(PairType(Temp, Entry->second));
777}
778
779void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
780 forwardInfo(MExpr->getBase(), MExpr);
781}
782
DeLesley Hutchins42525982013-08-29 22:36:05 +0000783
784void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000785 QualType ParamType = Param->getType();
786 ConsumedState ParamState = consumed::CS_None;
787
788 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
789 isConsumableType(ParamType))
790 ParamState = mapConsumableAttrState(ParamType);
791 else if (ParamType->isReferenceType() &&
792 isConsumableType(ParamType->getPointeeType()))
793 ParamState = consumed::CS_Unknown;
794
795 if (ParamState)
796 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000797}
798
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000799void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
800 if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) {
801 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
802
803 if (Entry != PropagationMap.end()) {
804 assert(Entry->second.isState() || Entry->second.isVar());
805
806 ConsumedState RetState = Entry->second.isState() ?
807 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
808
809 if (RetState != ExpectedState)
810 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
811 Ret->getReturnLoc(), stateToString(ExpectedState),
812 stateToString(RetState));
813 }
814 }
815}
816
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000817void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000818 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
819 if (Entry == PropagationMap.end()) return;
820
821 switch (UOp->getOpcode()) {
822 case UO_AddrOf:
823 PropagationMap.insert(PairType(UOp, Entry->second));
824 break;
825
826 case UO_LNot:
827 if (Entry->second.isTest() || Entry->second.isBinTest())
828 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
829 break;
830
831 default:
832 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000833 }
834}
835
DeLesley Hutchins66540852013-10-04 21:28:06 +0000836// TODO: See if I need to check for reference types here.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000837void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000838 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000839 if (Var->hasInit()) {
840 PropagationInfo PInfo =
841 PropagationMap.find(Var->getInit())->second;
842
843 StateMap->setState(Var, PInfo.isVar() ?
844 StateMap->getState(PInfo.getVar()) : PInfo.getState());
845
846 } else {
847 StateMap->setState(Var, consumed::CS_Unknown);
848 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000849 }
850}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000851}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000852
853namespace clang {
854namespace consumed {
855
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000856void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
857 ConsumedStateMap *ThenStates,
858 ConsumedStateMap *ElseStates) {
859
860 ConsumedState VarState = ThenStates->getState(Test.Var);
861
862 if (VarState == CS_Unknown) {
863 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins66540852013-10-04 21:28:06 +0000864 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000865
866 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
867 ThenStates->markUnreachable();
868
DeLesley Hutchins66540852013-10-04 21:28:06 +0000869 } else if (VarState == Test.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000870 ElseStates->markUnreachable();
871 }
872}
873
874void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
875 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
876
877 const VarTestResult &LTest = PInfo.getLTest(),
878 &RTest = PInfo.getRTest();
879
880 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
881 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
882
883 if (LTest.Var) {
884 if (PInfo.testEffectiveOp() == EO_And) {
885 if (LState == CS_Unknown) {
886 ThenStates->setState(LTest.Var, LTest.TestsFor);
887
888 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
889 ThenStates->markUnreachable();
890
891 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000892 if (RState == RTest.TestsFor)
893 ElseStates->markUnreachable();
894 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000895 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000896 }
897
898 } else {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000899 if (LState == CS_Unknown) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000900 ElseStates->setState(LTest.Var,
901 invertConsumedUnconsumed(LTest.TestsFor));
902
DeLesley Hutchins66540852013-10-04 21:28:06 +0000903 } else if (LState == LTest.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000904 ElseStates->markUnreachable();
905
906 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
907 isKnownState(RState)) {
908
DeLesley Hutchins66540852013-10-04 21:28:06 +0000909 if (RState == RTest.TestsFor)
910 ElseStates->markUnreachable();
911 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000912 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000913 }
914 }
915 }
916
917 if (RTest.Var) {
918 if (PInfo.testEffectiveOp() == EO_And) {
919 if (RState == CS_Unknown)
920 ThenStates->setState(RTest.Var, RTest.TestsFor);
921 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
922 ThenStates->markUnreachable();
923
DeLesley Hutchins66540852013-10-04 21:28:06 +0000924 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000925 if (RState == CS_Unknown)
926 ElseStates->setState(RTest.Var,
927 invertConsumedUnconsumed(RTest.TestsFor));
928 else if (RState == RTest.TestsFor)
929 ElseStates->markUnreachable();
930 }
931 }
932}
933
DeLesley Hutchins73858402013-10-09 18:30:24 +0000934bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
935 const CFGBlock *TargetBlock) {
936
937 assert(CurrBlock && "Block pointer must not be NULL");
938 assert(TargetBlock && "TargetBlock pointer must not be NULL");
939
940 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
941 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
942 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
943 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
944 return false;
945 }
946 return true;
947}
948
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000949void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
950 ConsumedStateMap *StateMap,
951 bool &AlreadyOwned) {
952
DeLesley Hutchins73858402013-10-09 18:30:24 +0000953 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000954
955 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
956
957 if (Entry) {
958 Entry->intersect(StateMap);
959
960 } else if (AlreadyOwned) {
961 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
962
963 } else {
964 StateMapsArray[Block->getBlockID()] = StateMap;
965 AlreadyOwned = true;
966 }
967}
968
969void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
970 ConsumedStateMap *StateMap) {
971
DeLesley Hutchins73858402013-10-09 18:30:24 +0000972 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000973
974 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
975
976 if (Entry) {
977 Entry->intersect(StateMap);
978 delete StateMap;
979
980 } else {
981 StateMapsArray[Block->getBlockID()] = StateMap;
982 }
983}
984
DeLesley Hutchins73858402013-10-09 18:30:24 +0000985ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
986 assert(Block && "Block pointer must not be NULL");
987 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
988
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000989 return StateMapsArray[Block->getBlockID()];
990}
991
DeLesley Hutchins73858402013-10-09 18:30:24 +0000992void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
993 unsigned int BlockID = Block->getBlockID();
994 delete StateMapsArray[BlockID];
995 StateMapsArray[BlockID] = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000996}
997
DeLesley Hutchins73858402013-10-09 18:30:24 +0000998ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
999 assert(Block && "Block pointer must not be NULL");
1000
1001 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1002 if (isBackEdgeTarget(Block)) {
1003 return new ConsumedStateMap(*StateMap);
1004 } else {
1005 StateMapsArray[Block->getBlockID()] = NULL;
1006 return StateMap;
1007 }
1008}
1009
1010bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1011 assert(From && "From block must not be NULL");
1012 assert(To && "From block must not be NULL");
1013
1014 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1015}
1016
1017bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1018 assert(Block != NULL && "Block pointer must not be NULL");
1019
1020 // Anything with less than two predecessors can't be the target of a back
1021 // edge.
1022 if (Block->pred_size() < 2)
1023 return false;
1024
1025 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1026 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1027 PE = Block->pred_end(); PI != PE; ++PI) {
1028 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1029 return true;
1030 }
1031 return false;
1032}
1033
1034ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001035 MapType::const_iterator Entry = Map.find(Var);
1036
1037 if (Entry != Map.end()) {
1038 return Entry->second;
1039
1040 } else {
1041 return CS_None;
1042 }
1043}
1044
1045void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1046 ConsumedState LocalState;
1047
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001048 if (this->From && this->From == Other->From && !Other->Reachable) {
1049 this->markUnreachable();
1050 return;
1051 }
1052
DeLesley Hutchins73858402013-10-09 18:30:24 +00001053 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1054 DMI != DME; ++DMI) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001055
1056 LocalState = this->getState(DMI->first);
1057
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001058 if (LocalState == CS_None)
1059 continue;
1060
1061 if (LocalState != DMI->second)
1062 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001063 }
1064}
1065
DeLesley Hutchins73858402013-10-09 18:30:24 +00001066void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1067 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1068 ConsumedWarningsHandlerBase &WarningsHandler) {
1069
1070 ConsumedState LocalState;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001071 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001072
1073 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1074 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1075
1076 LocalState = this->getState(DMI->first);
1077
1078 if (LocalState == CS_None)
1079 continue;
1080
1081 if (LocalState != DMI->second) {
1082 Map[DMI->first] = CS_Unknown;
1083 WarningsHandler.warnLoopStateMismatch(
1084 BlameLoc, DMI->first->getNameAsString());
1085 }
1086 }
1087}
1088
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001089void ConsumedStateMap::markUnreachable() {
1090 this->Reachable = false;
1091 Map.clear();
1092}
1093
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001094void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1095 Map[Var] = State;
1096}
1097
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001098void ConsumedStateMap::remove(const VarDecl *Var) {
1099 Map.erase(Var);
1100}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001101
DeLesley Hutchins73858402013-10-09 18:30:24 +00001102bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1103 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1104 DMI != DME; ++DMI) {
1105
1106 if (this->getState(DMI->first) != DMI->second)
1107 return true;
1108 }
1109
1110 return false;
1111}
1112
David Blaikiea33ab602013-09-06 01:28:43 +00001113void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1114 const FunctionDecl *D) {
1115 QualType ReturnType;
1116 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1117 ASTContext &CurrContext = AC.getASTContext();
1118 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1119 } else
1120 ReturnType = D->getCallResultType();
1121
1122 if (D->hasAttr<ReturnTypestateAttr>()) {
1123 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1124
1125 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1126 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1127 // FIXME: This should be removed when template instantiation propagates
1128 // attributes at template specialization definition, not
1129 // declaration. When it is removed the test needs to be enabled
1130 // in SemaDeclAttr.cpp.
1131 WarningsHandler.warnReturnTypestateForUnconsumableType(
1132 RTSAttr->getLocation(), ReturnType.getAsString());
1133 ExpectedReturnState = CS_None;
1134 } else
1135 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1136 } else if (isConsumableType(ReturnType))
1137 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1138 else
1139 ExpectedReturnState = CS_None;
1140}
1141
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001142bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1143 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001144
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001145 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1146 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001147
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001148 if (const IfStmt *IfNode =
1149 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001150
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001151 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001152
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001153 PInfo = Visitor.getInfo(Cond);
1154 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1155 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1156
1157 if (PInfo.isTest()) {
1158 CurrStates->setSource(Cond);
1159 FalseStates->setSource(Cond);
DeLesley Hutchins66540852013-10-04 21:28:06 +00001160 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001161
1162 } else if (PInfo.isBinTest()) {
1163 CurrStates->setSource(PInfo.testSourceNode());
1164 FalseStates->setSource(PInfo.testSourceNode());
DeLesley Hutchins66540852013-10-04 21:28:06 +00001165 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001166
1167 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001168 delete FalseStates;
1169 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001170 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001171
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001172 } else if (const BinaryOperator *BinOp =
1173 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1174
1175 PInfo = Visitor.getInfo(BinOp->getLHS());
1176 if (!PInfo.isTest()) {
1177 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1178 PInfo = Visitor.getInfo(BinOp->getRHS());
1179
1180 if (!PInfo.isTest()) {
1181 delete FalseStates;
1182 return false;
1183 }
1184
1185 } else {
1186 delete FalseStates;
1187 return false;
1188 }
1189 }
1190
1191 CurrStates->setSource(BinOp);
1192 FalseStates->setSource(BinOp);
1193
1194 const VarTestResult &Test = PInfo.getTest();
1195 ConsumedState VarState = CurrStates->getState(Test.Var);
1196
1197 if (BinOp->getOpcode() == BO_LAnd) {
1198 if (VarState == CS_Unknown)
1199 CurrStates->setState(Test.Var, Test.TestsFor);
1200 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1201 CurrStates->markUnreachable();
1202
1203 } else if (BinOp->getOpcode() == BO_LOr) {
1204 if (VarState == CS_Unknown)
1205 FalseStates->setState(Test.Var,
1206 invertConsumedUnconsumed(Test.TestsFor));
1207 else if (VarState == Test.TestsFor)
1208 FalseStates->markUnreachable();
1209 }
1210
1211 } else {
1212 delete FalseStates;
1213 return false;
1214 }
1215
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001216 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1217
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001218 if (*SI)
1219 BlockInfo.addInfo(*SI, CurrStates);
1220 else
1221 delete CurrStates;
1222
1223 if (*++SI)
1224 BlockInfo.addInfo(*SI, FalseStates);
1225 else
1226 delete FalseStates;
1227
1228 CurrStates = NULL;
1229 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001230}
1231
1232void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1233 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001234 if (!D)
1235 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001236
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001237 CFG *CFGraph = AC.getCFG();
1238 if (!CFGraph)
1239 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001240
David Blaikiea33ab602013-09-06 01:28:43 +00001241 determineExpectedReturnState(AC, D);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001242
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001243 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins73858402013-10-09 18:30:24 +00001244 // AC.getCFG()->viewCFG(LangOptions());
1245
1246 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001247
1248 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001249 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1250
1251 // Add all trackable parameters to the state map.
1252 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1253 PE = D->param_end(); PI != PE; ++PI) {
1254 Visitor.VisitParmVarDecl(*PI);
1255 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001256
1257 // Visit all of the function's basic blocks.
1258 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1259 E = SortedGraph->end(); I != E; ++I) {
1260
1261 const CFGBlock *CurrBlock = *I;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001262
1263 if (CurrStates == NULL)
1264 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001265
1266 if (!CurrStates) {
1267 continue;
1268
1269 } else if (!CurrStates->isReachable()) {
1270 delete CurrStates;
1271 CurrStates = NULL;
1272 continue;
1273 }
1274
1275 Visitor.reset(CurrStates);
1276
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001277 // Visit all of the basic block's statements.
1278 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1279 BE = CurrBlock->end(); BI != BE; ++BI) {
1280
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001281 switch (BI->getKind()) {
1282 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001283 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001284 break;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001285
1286 case CFGElement::TemporaryDtor: {
1287 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1288 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1289 PropagationInfo PInfo = Visitor.getInfo(BTE);
1290
1291 if (PInfo.isValid())
1292 Visitor.checkCallability(PInfo,
1293 DTor.getDestructorDecl(AC.getASTContext()),
1294 BTE->getExprLoc());
1295 break;
1296 }
1297
1298 case CFGElement::AutomaticObjectDtor: {
1299 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1300
1301 const VarDecl *Var = DTor.getVarDecl();
1302 ConsumedState VarState = CurrStates->getState(Var);
1303
1304 if (VarState != CS_None) {
1305 PropagationInfo PInfo(Var);
1306
1307 Visitor.checkCallability(PInfo,
1308 DTor.getDestructorDecl(AC.getASTContext()),
1309 getLastStmtLoc(CurrBlock));
1310
1311 CurrStates->remove(Var);
1312 }
1313 break;
1314 }
1315
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001316 default:
1317 break;
1318 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001319 }
1320
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001321 // TODO: Handle other forms of branching with precision, including while-
1322 // and for-loops. (Deferred)
1323 if (!splitState(CurrBlock, Visitor)) {
1324 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001325
DeLesley Hutchins73858402013-10-09 18:30:24 +00001326 if (CurrBlock->succ_size() > 1 ||
1327 (CurrBlock->succ_size() == 1 &&
1328 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001329
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001330 bool OwnershipTaken = false;
1331
1332 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1333 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1334
DeLesley Hutchins73858402013-10-09 18:30:24 +00001335 if (*SI == NULL) continue;
1336
1337 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1338 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1339 CurrStates,
1340 WarningsHandler);
1341
1342 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1343 BlockInfo.discardInfo(*SI);
1344 } else {
1345 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1346 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001347 }
1348
1349 if (!OwnershipTaken)
1350 delete CurrStates;
1351
1352 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001353 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001354 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001355 } // End of block iterator.
1356
1357 // Delete the last existing state map.
1358 delete CurrStates;
1359
1360 WarningsHandler.emitDiagnostics();
1361}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001362}} // end namespace clang::consumed