blob: f6fe78ac4619c3f32cd31ae94a5174189f26542a [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
Mehdi Amini9670f842016-07-18 19:02:11 +000015#include "clang/Analysis/Analyses/Consumed.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000016#include "clang/AST/ASTContext.h"
17#include "clang/AST/Attr.h"
18#include "clang/AST/DeclCXX.h"
19#include "clang/AST/ExprCXX.h"
20#include "clang/AST/RecursiveASTVisitor.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000021#include "clang/AST/StmtCXX.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000022#include "clang/AST/StmtVisitor.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000023#include "clang/AST/Type.h"
24#include "clang/Analysis/Analyses/PostOrderCFGView.h"
25#include "clang/Analysis/AnalysisContext.h"
26#include "clang/Analysis/CFG.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000027#include "clang/Basic/OperatorKinds.h"
28#include "clang/Basic/SourceLocation.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000029#include "llvm/ADT/DenseMap.h"
Ahmed Charlesdfca6f92014-03-09 11:36:40 +000030#include <memory>
DeLesley Hutchins48a31762013-08-12 21:20:55 +000031
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +000032// TODO: Adjust states of args to constructors in the same way that arguments to
33// function calls are handled.
34// TODO: Use information from tests in for- and 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
Angel Garcia Gomez637d1e62015-10-20 13:23:58 +000052ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
DeLesley Hutchins48a31762013-08-12 21:20:55 +000053
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.
Aaron Ballman35897d92014-04-28 14:56:59 +000057 for (const auto &B : *Block)
58 if (Optional<CFGStmt> CS = B.getAs<CFGStmt>())
DeLesley Hutchins65013202013-10-17 18:19:31 +000059 return CS->getStmt()->getLocStart();
DeLesley Hutchins65013202013-10-17 18:19:31 +000060
61 // Block is empty.
62 // If we have one successor, return the first statement in that block
63 if (Block->succ_size() == 1 && *Block->succ_begin())
64 return getFirstStmtLoc(*Block->succ_begin());
65
66 return SourceLocation();
67}
68
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +000069static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +000070 // Find the source location of the last statement in the block, if the block
71 // is not empty.
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +000072 if (const Stmt *StmtNode = Block->getTerminator()) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +000073 return StmtNode->getLocStart();
74 } else {
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +000075 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
76 BE = Block->rend(); BI != BE; ++BI) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +000077 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
78 return CS->getStmt()->getLocStart();
79 }
80 }
DeLesley Hutchins65013202013-10-17 18:19:31 +000081
82 // If we have one successor, return the first statement in that block
83 SourceLocation Loc;
84 if (Block->succ_size() == 1 && *Block->succ_begin())
85 Loc = getFirstStmtLoc(*Block->succ_begin());
86 if (Loc.isValid())
87 return Loc;
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +000088
DeLesley Hutchins65013202013-10-17 18:19:31 +000089 // If we have one predecessor, return the last statement in that block
90 if (Block->pred_size() == 1 && *Block->pred_begin())
91 return getLastStmtLoc(*Block->pred_begin());
92
93 return Loc;
DeLesley Hutchins3277a612013-10-09 18:30:24 +000094}
95
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000096static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
97 switch (State) {
98 case CS_Unconsumed:
99 return CS_Consumed;
100 case CS_Consumed:
101 return CS_Unconsumed;
102 case CS_None:
103 return CS_None;
104 case CS_Unknown:
105 return CS_Unknown;
106 }
107 llvm_unreachable("invalid enum");
108}
109
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000110static bool isCallableInState(const CallableWhenAttr *CWAttr,
111 ConsumedState State) {
112
Aaron Ballmana82eaa72014-05-02 13:35:42 +0000113 for (const auto &S : CWAttr->callableStates()) {
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000114 ConsumedState MappedAttrState = CS_None;
Aaron Ballmana82eaa72014-05-02 13:35:42 +0000115
116 switch (S) {
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000117 case CallableWhenAttr::Unknown:
118 MappedAttrState = CS_Unknown;
119 break;
120
121 case CallableWhenAttr::Unconsumed:
122 MappedAttrState = CS_Unconsumed;
123 break;
124
125 case CallableWhenAttr::Consumed:
126 MappedAttrState = CS_Consumed;
127 break;
128 }
129
130 if (MappedAttrState == State)
131 return true;
132 }
133
134 return false;
135}
136
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000137
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000138static bool isConsumableType(const QualType &QT) {
Chris Wailes93edffa2013-10-31 15:38:12 +0000139 if (QT->isPointerType() || QT->isReferenceType())
140 return false;
141
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000142 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
143 return RD->hasAttr<ConsumableAttr>();
Chris Wailes93edffa2013-10-31 15:38:12 +0000144
145 return false;
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000146}
147
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000148static bool isAutoCastType(const QualType &QT) {
149 if (QT->isPointerType() || QT->isReferenceType())
150 return false;
151
152 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
153 return RD->hasAttr<ConsumableAutoCastAttr>();
154
155 return false;
156}
157
158static bool isSetOnReadPtrType(const QualType &QT) {
159 if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl())
160 return RD->hasAttr<ConsumableSetOnReadAttr>();
161 return false;
162}
163
164
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000165static bool isKnownState(ConsumedState State) {
166 switch (State) {
167 case CS_Unconsumed:
168 case CS_Consumed:
169 return true;
170 case CS_None:
171 case CS_Unknown:
172 return false;
173 }
Aaron Ballmana21f4b82013-08-29 20:36:09 +0000174 llvm_unreachable("invalid enum");
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000175}
176
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000177static bool isRValueRef(QualType ParamType) {
178 return ParamType->isRValueReferenceType();
DeLesley Hutchins0bd25892013-10-18 19:25:18 +0000179}
180
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000181static bool isTestingFunction(const FunctionDecl *FunDecl) {
Chris Wailes9385f9f2013-10-29 20:28:41 +0000182 return FunDecl->hasAttr<TestTypestateAttr>();
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000183}
184
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000185static bool isPointerOrRef(QualType ParamType) {
186 return ParamType->isPointerType() || ParamType->isReferenceType();
DeLesley Hutchins0bd25892013-10-18 19:25:18 +0000187}
188
David Blaikie16f76d22013-09-06 01:28:43 +0000189static ConsumedState mapConsumableAttrState(const QualType QT) {
190 assert(isConsumableType(QT));
191
192 const ConsumableAttr *CAttr =
193 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
194
195 switch (CAttr->getDefaultState()) {
196 case ConsumableAttr::Unknown:
197 return CS_Unknown;
198 case ConsumableAttr::Unconsumed:
199 return CS_Unconsumed;
200 case ConsumableAttr::Consumed:
201 return CS_Consumed;
202 }
203 llvm_unreachable("invalid enum");
204}
205
DeLesley Hutchins69391772013-10-17 23:23:53 +0000206static ConsumedState
207mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
208 switch (PTAttr->getParamState()) {
209 case ParamTypestateAttr::Unknown:
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000210 return CS_Unknown;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000211 case ParamTypestateAttr::Unconsumed:
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000212 return CS_Unconsumed;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000213 case ParamTypestateAttr::Consumed:
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000214 return CS_Consumed;
215 }
216 llvm_unreachable("invalid_enum");
217}
218
Eric Christopherde156242013-09-03 20:43:00 +0000219static ConsumedState
220mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000221 switch (RTSAttr->getState()) {
222 case ReturnTypestateAttr::Unknown:
223 return CS_Unknown;
224 case ReturnTypestateAttr::Unconsumed:
225 return CS_Unconsumed;
226 case ReturnTypestateAttr::Consumed:
227 return CS_Consumed;
228 }
Eric Christopherde156242013-09-03 20:43:00 +0000229 llvm_unreachable("invalid enum");
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000230}
231
DeLesley Hutchins69391772013-10-17 23:23:53 +0000232static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
233 switch (STAttr->getNewState()) {
234 case SetTypestateAttr::Unknown:
235 return CS_Unknown;
236 case SetTypestateAttr::Unconsumed:
237 return CS_Unconsumed;
238 case SetTypestateAttr::Consumed:
239 return CS_Consumed;
240 }
241 llvm_unreachable("invalid_enum");
242}
243
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000244static StringRef stateToString(ConsumedState State) {
245 switch (State) {
246 case consumed::CS_None:
247 return "none";
248
249 case consumed::CS_Unknown:
250 return "unknown";
251
252 case consumed::CS_Unconsumed:
253 return "unconsumed";
254
255 case consumed::CS_Consumed:
256 return "consumed";
257 }
Reid Kleckner6454d0a2013-08-13 00:11:59 +0000258 llvm_unreachable("invalid enum");
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000259}
260
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000261static ConsumedState testsFor(const FunctionDecl *FunDecl) {
262 assert(isTestingFunction(FunDecl));
Chris Wailes9385f9f2013-10-29 20:28:41 +0000263 switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
264 case TestTypestateAttr::Unconsumed:
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000265 return CS_Unconsumed;
Chris Wailes9385f9f2013-10-29 20:28:41 +0000266 case TestTypestateAttr::Consumed:
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000267 return CS_Consumed;
268 }
269 llvm_unreachable("invalid enum");
270}
271
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000272namespace {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000273struct VarTestResult {
274 const VarDecl *Var;
275 ConsumedState TestsFor;
276};
277} // end anonymous::VarTestResult
278
279namespace clang {
280namespace consumed {
281
282enum EffectiveOp {
283 EO_And,
284 EO_Or
285};
286
287class PropagationInfo {
288 enum {
289 IT_None,
290 IT_State,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000291 IT_VarTest,
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000292 IT_BinTest,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000293 IT_Var,
294 IT_Tmp
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000295 } InfoType;
Eric Christopherf8a1baa2013-08-29 18:00:58 +0000296
297 struct BinTestTy {
298 const BinaryOperator *Source;
299 EffectiveOp EOp;
300 VarTestResult LTest;
301 VarTestResult RTest;
302 };
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000303
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000304 union {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000305 ConsumedState State;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000306 VarTestResult VarTest;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000307 const VarDecl *Var;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000308 const CXXBindTemporaryExpr *Tmp;
Eric Christopherf8a1baa2013-08-29 18:00:58 +0000309 BinTestTy BinTest;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000310 };
311
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000312public:
313 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000314
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000315 PropagationInfo(const VarTestResult &VarTest)
316 : InfoType(IT_VarTest), VarTest(VarTest) {}
317
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000318 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000319 : InfoType(IT_VarTest) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000320
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000321 VarTest.Var = Var;
322 VarTest.TestsFor = TestsFor;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000323 }
324
325 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
326 const VarTestResult &LTest, const VarTestResult &RTest)
327 : InfoType(IT_BinTest) {
328
329 BinTest.Source = Source;
330 BinTest.EOp = EOp;
331 BinTest.LTest = LTest;
332 BinTest.RTest = RTest;
333 }
334
335 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
336 const VarDecl *LVar, ConsumedState LTestsFor,
337 const VarDecl *RVar, ConsumedState RTestsFor)
338 : InfoType(IT_BinTest) {
339
340 BinTest.Source = Source;
341 BinTest.EOp = EOp;
342 BinTest.LTest.Var = LVar;
343 BinTest.LTest.TestsFor = LTestsFor;
344 BinTest.RTest.Var = RVar;
345 BinTest.RTest.TestsFor = RTestsFor;
346 }
347
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000348 PropagationInfo(ConsumedState State)
349 : InfoType(IT_State), State(State) {}
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000350
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000351 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000352 PropagationInfo(const CXXBindTemporaryExpr *Tmp)
353 : InfoType(IT_Tmp), Tmp(Tmp) {}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000354
355 const ConsumedState & getState() const {
356 assert(InfoType == IT_State);
357 return State;
358 }
359
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000360 const VarTestResult & getVarTest() const {
361 assert(InfoType == IT_VarTest);
362 return VarTest;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000363 }
364
365 const VarTestResult & getLTest() const {
366 assert(InfoType == IT_BinTest);
367 return BinTest.LTest;
368 }
369
370 const VarTestResult & getRTest() const {
371 assert(InfoType == IT_BinTest);
372 return BinTest.RTest;
373 }
374
375 const VarDecl * getVar() const {
376 assert(InfoType == IT_Var);
377 return Var;
378 }
379
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000380 const CXXBindTemporaryExpr * getTmp() const {
381 assert(InfoType == IT_Tmp);
382 return Tmp;
383 }
384
385 ConsumedState getAsState(const ConsumedStateMap *StateMap) const {
386 assert(isVar() || isTmp() || isState());
387
388 if (isVar())
389 return StateMap->getState(Var);
390 else if (isTmp())
391 return StateMap->getState(Tmp);
392 else if (isState())
393 return State;
394 else
395 return CS_None;
396 }
397
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000398 EffectiveOp testEffectiveOp() const {
399 assert(InfoType == IT_BinTest);
400 return BinTest.EOp;
401 }
402
403 const BinaryOperator * testSourceNode() const {
404 assert(InfoType == IT_BinTest);
405 return BinTest.Source;
406 }
407
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000408 inline bool isValid() const { return InfoType != IT_None; }
409 inline bool isState() const { return InfoType == IT_State; }
410 inline bool isVarTest() const { return InfoType == IT_VarTest; }
411 inline bool isBinTest() const { return InfoType == IT_BinTest; }
412 inline bool isVar() const { return InfoType == IT_Var; }
413 inline bool isTmp() const { return InfoType == IT_Tmp; }
414
415 bool isTest() const {
416 return InfoType == IT_VarTest || InfoType == IT_BinTest;
417 }
418
419 bool isPointerToValue() const {
420 return InfoType == IT_Var || InfoType == IT_Tmp;
421 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000422
423 PropagationInfo invertTest() const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000424 assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000425
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000426 if (InfoType == IT_VarTest) {
427 return PropagationInfo(VarTest.Var,
428 invertConsumedUnconsumed(VarTest.TestsFor));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000429
430 } else if (InfoType == IT_BinTest) {
431 return PropagationInfo(BinTest.Source,
432 BinTest.EOp == EO_And ? EO_Or : EO_And,
433 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
434 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
435 } else {
436 return PropagationInfo();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000437 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000438 }
439};
440
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000441static inline void
442setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
443 ConsumedState State) {
444
445 assert(PInfo.isVar() || PInfo.isTmp());
446
447 if (PInfo.isVar())
448 StateMap->setState(PInfo.getVar(), State);
449 else
450 StateMap->setState(PInfo.getTmp(), State);
451}
452
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000453class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000454
455 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
456 typedef std::pair<const Stmt *, PropagationInfo> PairType;
457 typedef MapType::iterator InfoEntry;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000458 typedef MapType::const_iterator ConstInfoEntry;
459
Reid Klecknere846dea2013-08-12 23:49:39 +0000460 AnalysisDeclContext &AC;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000461 ConsumedAnalyzer &Analyzer;
462 ConsumedStateMap *StateMap;
463 MapType PropagationMap;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000464
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000465 InfoEntry findInfo(const Expr *E) {
Tim Shen4a05bb82016-06-21 20:29:17 +0000466 if (auto Cleanups = dyn_cast<ExprWithCleanups>(E))
467 if (!Cleanups->cleanupsHaveSideEffects())
468 E = Cleanups->getSubExpr();
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000469 return PropagationMap.find(E->IgnoreParens());
470 }
471 ConstInfoEntry findInfo(const Expr *E) const {
Tim Shen4a05bb82016-06-21 20:29:17 +0000472 if (auto Cleanups = dyn_cast<ExprWithCleanups>(E))
473 if (!Cleanups->cleanupsHaveSideEffects())
474 E = Cleanups->getSubExpr();
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000475 return PropagationMap.find(E->IgnoreParens());
476 }
477 void insertInfo(const Expr *E, const PropagationInfo &PI) {
478 PropagationMap.insert(PairType(E->IgnoreParens(), PI));
479 }
480
481 void forwardInfo(const Expr *From, const Expr *To);
482 void copyInfo(const Expr *From, const Expr *To, ConsumedState CS);
483 ConsumedState getInfo(const Expr *From);
484 void setInfo(const Expr *To, ConsumedState NS);
485 void propagateReturnType(const Expr *Call, const FunctionDecl *Fun);
DeLesley Hutchins81218662013-10-18 23:11:49 +0000486
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000487public:
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000488 void checkCallability(const PropagationInfo &PInfo,
489 const FunctionDecl *FunDecl,
490 SourceLocation BlameLoc);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000491 bool handleCall(const CallExpr *Call, const Expr *ObjArg,
492 const FunctionDecl *FunD);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000493
494 void VisitBinaryOperator(const BinaryOperator *BinOp);
495 void VisitCallExpr(const CallExpr *Call);
496 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000497 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000498 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
499 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
500 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
501 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
502 void VisitDeclStmt(const DeclStmt *DelcS);
503 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
504 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000505 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000506 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000507 void VisitUnaryOperator(const UnaryOperator *UOp);
508 void VisitVarDecl(const VarDecl *Var);
Reid Klecknere846dea2013-08-12 23:49:39 +0000509
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000510 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
511 ConsumedStateMap *StateMap)
512 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000513
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000514 PropagationInfo getInfo(const Expr *StmtNode) const {
515 ConstInfoEntry Entry = findInfo(StmtNode);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000516
517 if (Entry != PropagationMap.end())
518 return Entry->second;
519 else
520 return PropagationInfo();
521 }
522
523 void reset(ConsumedStateMap *NewStateMap) {
524 StateMap = NewStateMap;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000525 }
526};
527
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000528
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000529void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
530 InfoEntry Entry = findInfo(From);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000531 if (Entry != PropagationMap.end())
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000532 insertInfo(To, Entry->second);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000533}
534
535
536// Create a new state for To, which is initialized to the state of From.
537// If NS is not CS_None, sets the state of From to NS.
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000538void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000539 ConsumedState NS) {
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000540 InfoEntry Entry = findInfo(From);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000541 if (Entry != PropagationMap.end()) {
542 PropagationInfo& PInfo = Entry->second;
543 ConsumedState CS = PInfo.getAsState(StateMap);
544 if (CS != CS_None)
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000545 insertInfo(To, PropagationInfo(CS));
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000546 if (NS != CS_None && PInfo.isPointerToValue())
547 setStateForVarOrTmp(StateMap, PInfo, NS);
548 }
549}
550
551
552// Get the ConsumedState for From
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000553ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) {
554 InfoEntry Entry = findInfo(From);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000555 if (Entry != PropagationMap.end()) {
556 PropagationInfo& PInfo = Entry->second;
557 return PInfo.getAsState(StateMap);
558 }
559 return CS_None;
560}
561
562
563// If we already have info for To then update it, otherwise create a new entry.
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000564void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
565 InfoEntry Entry = findInfo(To);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000566 if (Entry != PropagationMap.end()) {
567 PropagationInfo& PInfo = Entry->second;
568 if (PInfo.isPointerToValue())
569 setStateForVarOrTmp(StateMap, PInfo, NS);
570 } else if (NS != CS_None) {
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000571 insertInfo(To, PropagationInfo(NS));
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000572 }
573}
574
575
576
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000577void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000578 const FunctionDecl *FunDecl,
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000579 SourceLocation BlameLoc) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000580 assert(!PInfo.isTest());
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000581
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000582 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000583 if (!CWAttr)
584 return;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000585
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000586 if (PInfo.isVar()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000587 ConsumedState VarState = StateMap->getState(PInfo.getVar());
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000588
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000589 if (VarState == CS_None || isCallableInState(CWAttr, VarState))
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000590 return;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000591
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000592 Analyzer.WarningsHandler.warnUseInInvalidState(
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000593 FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000594 stateToString(VarState), BlameLoc);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000595
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000596 } else {
597 ConsumedState TmpState = PInfo.getAsState(StateMap);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000598
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000599 if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000600 return;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000601
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000602 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000603 FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000604 }
605}
606
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000607
608// Factors out common behavior for function, method, and operator calls.
609// Check parameters and set parameter state if necessary.
610// Returns true if the state of ObjArg is set, or false otherwise.
611bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
612 const FunctionDecl *FunD) {
613 unsigned Offset = 0;
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000614 if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
615 Offset = 1; // first argument is 'this'
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000616
617 // check explicit parameters
618 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
619 // Skip variable argument lists.
620 if (Index - Offset >= FunD->getNumParams())
621 break;
622
623 const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
624 QualType ParamType = Param->getType();
625
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000626 InfoEntry Entry = findInfo(Call->getArg(Index));
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000627
628 if (Entry == PropagationMap.end() || Entry->second.isTest())
629 continue;
630 PropagationInfo PInfo = Entry->second;
631
632 // Check that the parameter is in the correct state.
633 if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
634 ConsumedState ParamState = PInfo.getAsState(StateMap);
635 ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
636
637 if (ParamState != ExpectedState)
638 Analyzer.WarningsHandler.warnParamTypestateMismatch(
639 Call->getArg(Index)->getExprLoc(),
640 stateToString(ExpectedState), stateToString(ParamState));
641 }
642
643 if (!(Entry->second.isVar() || Entry->second.isTmp()))
644 continue;
645
646 // Adjust state on the caller side.
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000647 if (isRValueRef(ParamType))
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000648 setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
649 else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
650 setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000651 else if (isPointerOrRef(ParamType) &&
652 (!ParamType->getPointeeType().isConstQualified() ||
653 isSetOnReadPtrType(ParamType)))
654 setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000655 }
656
657 if (!ObjArg)
658 return false;
659
660 // check implicit 'self' parameter, if present
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000661 InfoEntry Entry = findInfo(ObjArg);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000662 if (Entry != PropagationMap.end()) {
663 PropagationInfo PInfo = Entry->second;
664 checkCallability(PInfo, FunD, Call->getExprLoc());
665
666 if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) {
667 if (PInfo.isVar()) {
668 StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
669 return true;
670 }
671 else if (PInfo.isTmp()) {
672 StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
673 return true;
674 }
675 }
676 else if (isTestingFunction(FunD) && PInfo.isVar()) {
677 PropagationMap.insert(PairType(Call,
678 PropagationInfo(PInfo.getVar(), testsFor(FunD))));
679 }
680 }
681 return false;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000682}
683
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000684
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000685void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000686 const FunctionDecl *Fun) {
687 QualType RetType = Fun->getCallResultType();
688 if (RetType->isReferenceType())
689 RetType = RetType->getPointeeType();
690
691 if (isConsumableType(RetType)) {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000692 ConsumedState ReturnState;
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000693 if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>())
694 ReturnState = mapReturnTypestateAttrState(RTA);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000695 else
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000696 ReturnState = mapConsumableAttrState(RetType);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000697
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000698 PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000699 }
700}
701
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000702
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000703void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
704 switch (BinOp->getOpcode()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000705 case BO_LAnd:
706 case BO_LOr : {
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000707 InfoEntry LEntry = findInfo(BinOp->getLHS()),
708 REntry = findInfo(BinOp->getRHS());
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000709
710 VarTestResult LTest, RTest;
711
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000712 if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
713 LTest = LEntry->second.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000714
715 } else {
Craig Topper25542942014-05-20 04:30:07 +0000716 LTest.Var = nullptr;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000717 LTest.TestsFor = CS_None;
718 }
719
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000720 if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
721 RTest = REntry->second.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000722
723 } else {
Craig Topper25542942014-05-20 04:30:07 +0000724 RTest.Var = nullptr;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000725 RTest.TestsFor = CS_None;
726 }
Craig Topper25542942014-05-20 04:30:07 +0000727
728 if (!(LTest.Var == nullptr && RTest.Var == nullptr))
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000729 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
730 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
731
732 break;
733 }
734
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000735 case BO_PtrMemD:
736 case BO_PtrMemI:
737 forwardInfo(BinOp->getLHS(), BinOp);
738 break;
739
740 default:
741 break;
742 }
743}
744
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000745void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000746 const FunctionDecl *FunDecl = Call->getDirectCallee();
747 if (!FunDecl)
748 return;
749
750 // Special case for the std::move function.
751 // TODO: Make this more specific. (Deferred)
Richard Trieuc771d5d2014-05-28 02:16:01 +0000752 if (Call->getNumArgs() == 1 && FunDecl->getNameAsString() == "move" &&
753 FunDecl->isInStdNamespace()) {
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000754 copyInfo(Call->getArg(0), Call, CS_Consumed);
755 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000756 }
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000757
Craig Topper25542942014-05-20 04:30:07 +0000758 handleCall(Call, nullptr, FunDecl);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000759 propagateReturnType(Call, FunDecl);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000760}
761
762void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000763 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000764}
765
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000766void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
767 const CXXBindTemporaryExpr *Temp) {
768
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000769 InfoEntry Entry = findInfo(Temp->getSubExpr());
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000770
771 if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
772 StateMap->setState(Temp, Entry->second.getAsState(StateMap));
773 PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
774 }
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000775}
776
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000777void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
778 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Klecknere846dea2013-08-12 23:49:39 +0000779
780 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000781 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
782
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000783 if (!isConsumableType(ThisType))
784 return;
785
786 // FIXME: What should happen if someone annotates the move constructor?
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000787 if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
788 // TODO: Adjust state of args appropriately.
789 ConsumedState RetState = mapReturnTypestateAttrState(RTA);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000790 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
791 } else if (Constructor->isDefaultConstructor()) {
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000792 PropagationMap.insert(PairType(Call,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000793 PropagationInfo(consumed::CS_Consumed)));
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000794 } else if (Constructor->isMoveConstructor()) {
795 copyInfo(Call->getArg(0), Call, CS_Consumed);
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000796 } else if (Constructor->isCopyConstructor()) {
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000797 // Copy state from arg. If setStateOnRead then set arg to CS_Unknown.
798 ConsumedState NS =
799 isSetOnReadPtrType(Constructor->getThisType(CurrContext)) ?
800 CS_Unknown : CS_None;
801 copyInfo(Call->getArg(0), Call, NS);
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000802 } else {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000803 // TODO: Adjust state of args appropriately.
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000804 ConsumedState RetState = mapConsumableAttrState(ThisType);
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000805 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000806 }
807}
808
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000809
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000810void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000811 const CXXMemberCallExpr *Call) {
812 CXXMethodDecl* MD = Call->getMethodDecl();
813 if (!MD)
814 return;
815
816 handleCall(Call, Call->getImplicitObjectArgument(), MD);
817 propagateReturnType(Call, MD);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000818}
819
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000820
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000821void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000822 const CXXOperatorCallExpr *Call) {
823
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000824 const FunctionDecl *FunDecl =
825 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000826 if (!FunDecl) return;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000827
828 if (Call->getOperator() == OO_Equal) {
829 ConsumedState CS = getInfo(Call->getArg(1));
830 if (!handleCall(Call, Call->getArg(0), FunDecl))
831 setInfo(Call->getArg(0), CS);
832 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000833 }
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000834
835 if (const CXXMemberCallExpr *MCall = dyn_cast<CXXMemberCallExpr>(Call))
836 handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
837 else
838 handleCall(Call, Call->getArg(0), FunDecl);
839
840 propagateReturnType(Call, FunDecl);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000841}
842
843void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
844 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
845 if (StateMap->getState(Var) != consumed::CS_None)
846 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
847}
848
849void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
Aaron Ballman535bbcc2014-03-14 17:01:24 +0000850 for (const auto *DI : DeclS->decls())
851 if (isa<VarDecl>(DI))
852 VisitVarDecl(cast<VarDecl>(DI));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000853
854 if (DeclS->isSingleDecl())
855 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
856 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
857}
858
859void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
860 const MaterializeTemporaryExpr *Temp) {
861
Chris Wailes44930882013-10-24 14:28:17 +0000862 forwardInfo(Temp->GetTemporaryExpr(), Temp);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000863}
864
865void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
866 forwardInfo(MExpr->getBase(), MExpr);
867}
868
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000869
870void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikie16f76d22013-09-06 01:28:43 +0000871 QualType ParamType = Param->getType();
872 ConsumedState ParamState = consumed::CS_None;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000873
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000874 if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
875 ParamState = mapParamTypestateAttrState(PTA);
876 else if (isConsumableType(ParamType))
877 ParamState = mapConsumableAttrState(ParamType);
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000878 else if (isRValueRef(ParamType) &&
879 isConsumableType(ParamType->getPointeeType()))
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000880 ParamState = mapConsumableAttrState(ParamType->getPointeeType());
881 else if (ParamType->isReferenceType() &&
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000882 isConsumableType(ParamType->getPointeeType()))
David Blaikie16f76d22013-09-06 01:28:43 +0000883 ParamState = consumed::CS_Unknown;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000884
885 if (ParamState != CS_None)
David Blaikie16f76d22013-09-06 01:28:43 +0000886 StateMap->setState(Param, ParamState);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000887}
888
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000889void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000890 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
891
892 if (ExpectedState != CS_None) {
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000893 InfoEntry Entry = findInfo(Ret->getRetValue());
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000894
895 if (Entry != PropagationMap.end()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000896 ConsumedState RetState = Entry->second.getAsState(StateMap);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000897
898 if (RetState != ExpectedState)
899 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
900 Ret->getReturnLoc(), stateToString(ExpectedState),
901 stateToString(RetState));
902 }
903 }
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000904
905 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
906 Analyzer.WarningsHandler);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000907}
908
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000909void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000910 InfoEntry Entry = findInfo(UOp->getSubExpr());
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000911 if (Entry == PropagationMap.end()) return;
912
913 switch (UOp->getOpcode()) {
914 case UO_AddrOf:
915 PropagationMap.insert(PairType(UOp, Entry->second));
916 break;
917
918 case UO_LNot:
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000919 if (Entry->second.isTest())
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000920 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
921 break;
922
923 default:
924 break;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000925 }
926}
927
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000928// TODO: See if I need to check for reference types here.
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000929void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000930 if (isConsumableType(Var->getType())) {
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000931 if (Var->hasInit()) {
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000932 MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit());
DeLesley Hutchins81218662013-10-18 23:11:49 +0000933 if (VIT != PropagationMap.end()) {
934 PropagationInfo PInfo = VIT->second;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000935 ConsumedState St = PInfo.getAsState(StateMap);
936
DeLesley Hutchins81218662013-10-18 23:11:49 +0000937 if (St != consumed::CS_None) {
938 StateMap->setState(Var, St);
939 return;
940 }
941 }
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000942 }
DeLesley Hutchins81218662013-10-18 23:11:49 +0000943 // Otherwise
944 StateMap->setState(Var, consumed::CS_Unknown);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000945 }
946}
Alexander Kornienkoab9db512015-06-22 23:07:51 +0000947}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000948
949namespace clang {
950namespace consumed {
951
Benjamin Kramer3a743452015-03-09 15:03:32 +0000952static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test,
953 ConsumedStateMap *ThenStates,
954 ConsumedStateMap *ElseStates) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000955 ConsumedState VarState = ThenStates->getState(Test.Var);
956
957 if (VarState == CS_Unknown) {
958 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000959 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000960
961 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
962 ThenStates->markUnreachable();
963
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000964 } else if (VarState == Test.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000965 ElseStates->markUnreachable();
966 }
967}
968
Benjamin Kramer3a743452015-03-09 15:03:32 +0000969static void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
970 ConsumedStateMap *ThenStates,
971 ConsumedStateMap *ElseStates) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000972 const VarTestResult &LTest = PInfo.getLTest(),
973 &RTest = PInfo.getRTest();
974
975 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
976 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
977
978 if (LTest.Var) {
979 if (PInfo.testEffectiveOp() == EO_And) {
980 if (LState == CS_Unknown) {
981 ThenStates->setState(LTest.Var, LTest.TestsFor);
982
983 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
984 ThenStates->markUnreachable();
985
986 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000987 if (RState == RTest.TestsFor)
988 ElseStates->markUnreachable();
989 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000990 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000991 }
992
993 } else {
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000994 if (LState == CS_Unknown) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000995 ElseStates->setState(LTest.Var,
996 invertConsumedUnconsumed(LTest.TestsFor));
997
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000998 } else if (LState == LTest.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000999 ElseStates->markUnreachable();
1000
1001 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
1002 isKnownState(RState)) {
1003
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001004 if (RState == RTest.TestsFor)
1005 ElseStates->markUnreachable();
1006 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001007 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001008 }
1009 }
1010 }
1011
1012 if (RTest.Var) {
1013 if (PInfo.testEffectiveOp() == EO_And) {
1014 if (RState == CS_Unknown)
1015 ThenStates->setState(RTest.Var, RTest.TestsFor);
1016 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
1017 ThenStates->markUnreachable();
1018
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001019 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001020 if (RState == CS_Unknown)
1021 ElseStates->setState(RTest.Var,
1022 invertConsumedUnconsumed(RTest.TestsFor));
1023 else if (RState == RTest.TestsFor)
1024 ElseStates->markUnreachable();
1025 }
1026 }
1027}
1028
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001029bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1030 const CFGBlock *TargetBlock) {
1031
1032 assert(CurrBlock && "Block pointer must not be NULL");
1033 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1034
1035 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1036 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1037 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1038 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1039 return false;
1040 }
1041 return true;
1042}
1043
David Blaikie86d8cf32015-08-14 01:26:19 +00001044void ConsumedBlockInfo::addInfo(
1045 const CFGBlock *Block, ConsumedStateMap *StateMap,
1046 std::unique_ptr<ConsumedStateMap> &OwnedStateMap) {
1047
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001048 assert(Block && "Block pointer must not be NULL");
David Blaikie86d8cf32015-08-14 01:26:19 +00001049
1050 auto &Entry = StateMapsArray[Block->getBlockID()];
1051
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001052 if (Entry) {
David Blaikie86d8cf32015-08-14 01:26:19 +00001053 Entry->intersect(*StateMap);
1054 } else if (OwnedStateMap)
1055 Entry = std::move(OwnedStateMap);
1056 else
1057 Entry = llvm::make_unique<ConsumedStateMap>(*StateMap);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001058}
1059
1060void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
David Blaikie86d8cf32015-08-14 01:26:19 +00001061 std::unique_ptr<ConsumedStateMap> StateMap) {
Craig Topper25542942014-05-20 04:30:07 +00001062
1063 assert(Block && "Block pointer must not be NULL");
1064
David Blaikie86d8cf32015-08-14 01:26:19 +00001065 auto &Entry = StateMapsArray[Block->getBlockID()];
1066
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001067 if (Entry) {
David Blaikie86d8cf32015-08-14 01:26:19 +00001068 Entry->intersect(*StateMap);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001069 } else {
David Blaikie86d8cf32015-08-14 01:26:19 +00001070 Entry = std::move(StateMap);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001071 }
1072}
1073
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001074ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1075 assert(Block && "Block pointer must not be NULL");
1076 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
David Blaikie86d8cf32015-08-14 01:26:19 +00001077
1078 return StateMapsArray[Block->getBlockID()].get();
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001079}
1080
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001081void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
David Blaikie86d8cf32015-08-14 01:26:19 +00001082 StateMapsArray[Block->getBlockID()] = nullptr;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001083}
1084
David Blaikie86d8cf32015-08-14 01:26:19 +00001085std::unique_ptr<ConsumedStateMap>
1086ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001087 assert(Block && "Block pointer must not be NULL");
David Blaikie86d8cf32015-08-14 01:26:19 +00001088
1089 auto &Entry = StateMapsArray[Block->getBlockID()];
1090 return isBackEdgeTarget(Block) ? llvm::make_unique<ConsumedStateMap>(*Entry)
1091 : std::move(Entry);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001092}
1093
1094bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1095 assert(From && "From block must not be NULL");
1096 assert(To && "From block must not be NULL");
1097
1098 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1099}
1100
1101bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
Craig Topper25542942014-05-20 04:30:07 +00001102 assert(Block && "Block pointer must not be NULL");
1103
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001104 // Anything with less than two predecessors can't be the target of a back
1105 // edge.
1106 if (Block->pred_size() < 2)
1107 return false;
1108
1109 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1110 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1111 PE = Block->pred_end(); PI != PE; ++PI) {
1112 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1113 return true;
1114 }
1115 return false;
1116}
1117
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001118void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1119 ConsumedWarningsHandlerBase &WarningsHandler) const {
1120
Aaron Ballman35897d92014-04-28 14:56:59 +00001121 for (const auto &DM : VarMap) {
1122 if (isa<ParmVarDecl>(DM.first)) {
1123 const ParmVarDecl *Param = cast<ParmVarDecl>(DM.first);
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001124 const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001125
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001126 if (!RTA)
1127 continue;
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001128
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001129 ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
Aaron Ballman35897d92014-04-28 14:56:59 +00001130 if (DM.second != ExpectedState)
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001131 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1132 Param->getNameAsString(), stateToString(ExpectedState),
Aaron Ballman35897d92014-04-28 14:56:59 +00001133 stateToString(DM.second));
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001134 }
1135 }
1136}
1137
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001138void ConsumedStateMap::clearTemporaries() {
1139 TmpMap.clear();
1140}
1141
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001142ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001143 VarMapType::const_iterator Entry = VarMap.find(Var);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001144
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001145 if (Entry != VarMap.end())
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001146 return Entry->second;
1147
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001148 return CS_None;
1149}
1150
1151ConsumedState
1152ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
1153 TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
1154
1155 if (Entry != TmpMap.end())
1156 return Entry->second;
1157
1158 return CS_None;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001159}
1160
David Blaikie86d8cf32015-08-14 01:26:19 +00001161void ConsumedStateMap::intersect(const ConsumedStateMap &Other) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001162 ConsumedState LocalState;
David Blaikie86d8cf32015-08-14 01:26:19 +00001163
1164 if (this->From && this->From == Other.From && !Other.Reachable) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001165 this->markUnreachable();
1166 return;
1167 }
David Blaikie86d8cf32015-08-14 01:26:19 +00001168
1169 for (const auto &DM : Other.VarMap) {
Aaron Ballman35897d92014-04-28 14:56:59 +00001170 LocalState = this->getState(DM.first);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001171
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001172 if (LocalState == CS_None)
1173 continue;
1174
Aaron Ballman35897d92014-04-28 14:56:59 +00001175 if (LocalState != DM.second)
1176 VarMap[DM.first] = CS_Unknown;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001177 }
1178}
1179
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001180void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1181 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1182 ConsumedWarningsHandlerBase &WarningsHandler) {
1183
1184 ConsumedState LocalState;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001185 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001186
Aaron Ballman35897d92014-04-28 14:56:59 +00001187 for (const auto &DM : LoopBackStates->VarMap) {
1188 LocalState = this->getState(DM.first);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001189
1190 if (LocalState == CS_None)
1191 continue;
1192
Aaron Ballman35897d92014-04-28 14:56:59 +00001193 if (LocalState != DM.second) {
1194 VarMap[DM.first] = CS_Unknown;
Aaron Ballmanfe46e622014-04-28 13:01:32 +00001195 WarningsHandler.warnLoopStateMismatch(BlameLoc,
Aaron Ballman35897d92014-04-28 14:56:59 +00001196 DM.first->getNameAsString());
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001197 }
1198 }
1199}
1200
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001201void ConsumedStateMap::markUnreachable() {
1202 this->Reachable = false;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001203 VarMap.clear();
1204 TmpMap.clear();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001205}
1206
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001207void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001208 VarMap[Var] = State;
1209}
1210
1211void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
1212 ConsumedState State) {
1213 TmpMap[Tmp] = State;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001214}
1215
Manuel Klimekb33bded2014-05-08 11:50:00 +00001216void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
1217 TmpMap.erase(Tmp);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001218}
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001219
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001220bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
Aaron Ballman35897d92014-04-28 14:56:59 +00001221 for (const auto &DM : Other->VarMap)
1222 if (this->getState(DM.first) != DM.second)
Aaron Ballmanfe46e622014-04-28 13:01:32 +00001223 return true;
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001224 return false;
1225}
1226
David Blaikie16f76d22013-09-06 01:28:43 +00001227void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1228 const FunctionDecl *D) {
1229 QualType ReturnType;
1230 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1231 ASTContext &CurrContext = AC.getASTContext();
1232 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1233 } else
1234 ReturnType = D->getCallResultType();
1235
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001236 if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
David Blaikie16f76d22013-09-06 01:28:43 +00001237 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1238 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1239 // FIXME: This should be removed when template instantiation propagates
1240 // attributes at template specialization definition, not
1241 // declaration. When it is removed the test needs to be enabled
1242 // in SemaDeclAttr.cpp.
1243 WarningsHandler.warnReturnTypestateForUnconsumableType(
1244 RTSAttr->getLocation(), ReturnType.getAsString());
1245 ExpectedReturnState = CS_None;
1246 } else
1247 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +00001248 } else if (isConsumableType(ReturnType)) {
1249 if (isAutoCastType(ReturnType)) // We can auto-cast the state to the
1250 ExpectedReturnState = CS_None; // expected state.
1251 else
1252 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1253 }
David Blaikie16f76d22013-09-06 01:28:43 +00001254 else
1255 ExpectedReturnState = CS_None;
1256}
1257
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001258bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1259 const ConsumedStmtVisitor &Visitor) {
Ahmed Charlesb8984322014-03-07 20:03:18 +00001260
1261 std::unique_ptr<ConsumedStateMap> FalseStates(
1262 new ConsumedStateMap(*CurrStates));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001263 PropagationInfo PInfo;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001264
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001265 if (const IfStmt *IfNode =
1266 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001267
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +00001268 const Expr *Cond = IfNode->getCond();
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001269
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001270 PInfo = Visitor.getInfo(Cond);
1271 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1272 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1273
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001274 if (PInfo.isVarTest()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001275 CurrStates->setSource(Cond);
1276 FalseStates->setSource(Cond);
David Blaikie86d8cf32015-08-14 01:26:19 +00001277 splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates.get(),
Chris Wailes2dc8c422013-10-25 15:33:28 +00001278 FalseStates.get());
David Blaikie86d8cf32015-08-14 01:26:19 +00001279
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001280 } else if (PInfo.isBinTest()) {
1281 CurrStates->setSource(PInfo.testSourceNode());
1282 FalseStates->setSource(PInfo.testSourceNode());
David Blaikie86d8cf32015-08-14 01:26:19 +00001283 splitVarStateForIfBinOp(PInfo, CurrStates.get(), FalseStates.get());
1284
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001285 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001286 return false;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001287 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001288
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001289 } else if (const BinaryOperator *BinOp =
1290 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1291
1292 PInfo = Visitor.getInfo(BinOp->getLHS());
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001293 if (!PInfo.isVarTest()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001294 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1295 PInfo = Visitor.getInfo(BinOp->getRHS());
1296
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001297 if (!PInfo.isVarTest())
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001298 return false;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001299
1300 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001301 return false;
1302 }
1303 }
1304
1305 CurrStates->setSource(BinOp);
1306 FalseStates->setSource(BinOp);
1307
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001308 const VarTestResult &Test = PInfo.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001309 ConsumedState VarState = CurrStates->getState(Test.Var);
1310
1311 if (BinOp->getOpcode() == BO_LAnd) {
1312 if (VarState == CS_Unknown)
1313 CurrStates->setState(Test.Var, Test.TestsFor);
1314 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1315 CurrStates->markUnreachable();
1316
1317 } else if (BinOp->getOpcode() == BO_LOr) {
1318 if (VarState == CS_Unknown)
1319 FalseStates->setState(Test.Var,
1320 invertConsumedUnconsumed(Test.TestsFor));
1321 else if (VarState == Test.TestsFor)
1322 FalseStates->markUnreachable();
1323 }
1324
1325 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001326 return false;
1327 }
1328
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001329 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1330
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001331 if (*SI)
David Blaikie86d8cf32015-08-14 01:26:19 +00001332 BlockInfo.addInfo(*SI, std::move(CurrStates));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001333 else
David Blaikie86d8cf32015-08-14 01:26:19 +00001334 CurrStates = nullptr;
Ahmed Charles9a16beb2014-03-07 19:33:25 +00001335
David Blaikie86d8cf32015-08-14 01:26:19 +00001336 if (*++SI)
1337 BlockInfo.addInfo(*SI, std::move(FalseStates));
1338
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001339 return true;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001340}
1341
1342void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1343 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001344 if (!D)
1345 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001346
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001347 CFG *CFGraph = AC.getCFG();
1348 if (!CFGraph)
1349 return;
DeLesley Hutchins65013202013-10-17 18:19:31 +00001350
David Blaikie16f76d22013-09-06 01:28:43 +00001351 determineExpectedReturnState(AC, D);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001352
Artyom Skrobov27720762014-09-23 08:34:41 +00001353 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001354 // AC.getCFG()->viewCFG(LangOptions());
1355
1356 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
David Blaikie86d8cf32015-08-14 01:26:19 +00001357
1358 CurrStates = llvm::make_unique<ConsumedStateMap>();
1359 ConsumedStmtVisitor Visitor(AC, *this, CurrStates.get());
1360
DeLesley Hutchinsb570c132013-08-29 22:36:05 +00001361 // Add all trackable parameters to the state map.
David Majnemer59f77922016-06-24 04:05:48 +00001362 for (const auto *PI : D->parameters())
Aaron Ballmanf6bf62e2014-03-07 15:12:56 +00001363 Visitor.VisitParmVarDecl(PI);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001364
1365 // Visit all of the function's basic blocks.
Aaron Ballmanfe46e622014-04-28 13:01:32 +00001366 for (const auto *CurrBlock : *SortedGraph) {
Craig Topper25542942014-05-20 04:30:07 +00001367 if (!CurrStates)
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001368 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001369
1370 if (!CurrStates) {
1371 continue;
1372
1373 } else if (!CurrStates->isReachable()) {
Craig Topper25542942014-05-20 04:30:07 +00001374 CurrStates = nullptr;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001375 continue;
1376 }
David Blaikie86d8cf32015-08-14 01:26:19 +00001377
1378 Visitor.reset(CurrStates.get());
1379
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001380 // Visit all of the basic block's statements.
Aaron Ballman35897d92014-04-28 14:56:59 +00001381 for (const auto &B : *CurrBlock) {
1382 switch (B.getKind()) {
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001383 case CFGElement::Statement:
Aaron Ballman35897d92014-04-28 14:56:59 +00001384 Visitor.Visit(B.castAs<CFGStmt>().getStmt());
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001385 break;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001386
1387 case CFGElement::TemporaryDtor: {
Aaron Ballman35897d92014-04-28 14:56:59 +00001388 const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001389 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001390
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001391 Visitor.checkCallability(PropagationInfo(BTE),
1392 DTor.getDestructorDecl(AC.getASTContext()),
1393 BTE->getExprLoc());
Manuel Klimekb33bded2014-05-08 11:50:00 +00001394 CurrStates->remove(BTE);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001395 break;
1396 }
1397
1398 case CFGElement::AutomaticObjectDtor: {
Aaron Ballman35897d92014-04-28 14:56:59 +00001399 const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001400 SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001401 const VarDecl *Var = DTor.getVarDecl();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001402
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001403 Visitor.checkCallability(PropagationInfo(Var),
1404 DTor.getDestructorDecl(AC.getASTContext()),
1405 Loc);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001406 break;
1407 }
1408
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001409 default:
1410 break;
1411 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001412 }
1413
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001414 // TODO: Handle other forms of branching with precision, including while-
1415 // and for-loops. (Deferred)
1416 if (!splitState(CurrBlock, Visitor)) {
Craig Topper25542942014-05-20 04:30:07 +00001417 CurrStates->setSource(nullptr);
1418
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001419 if (CurrBlock->succ_size() > 1 ||
1420 (CurrBlock->succ_size() == 1 &&
1421 (*CurrBlock->succ_begin())->pred_size() > 1)) {
David Blaikie86d8cf32015-08-14 01:26:19 +00001422
1423 auto *RawState = CurrStates.get();
1424
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001425 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1426 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
Craig Topper25542942014-05-20 04:30:07 +00001427
1428 if (*SI == nullptr) continue;
1429
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001430 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
David Blaikie86d8cf32015-08-14 01:26:19 +00001431 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(
1432 *SI, CurrBlock, RawState, WarningsHandler);
1433
DeLesley Hutchins773ba372015-04-15 22:32:44 +00001434 if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI))
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001435 BlockInfo.discardInfo(*SI);
1436 } else {
David Blaikie86d8cf32015-08-14 01:26:19 +00001437 BlockInfo.addInfo(*SI, RawState, CurrStates);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001438 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001439 }
Craig Topper25542942014-05-20 04:30:07 +00001440
1441 CurrStates = nullptr;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001442 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001443 }
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001444
1445 if (CurrBlock == &AC.getCFG()->getExit() &&
1446 D->getCallResultType()->isVoidType())
1447 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1448 WarningsHandler);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001449 } // End of block iterator.
1450
1451 // Delete the last existing state map.
David Blaikie86d8cf32015-08-14 01:26:19 +00001452 CurrStates = nullptr;
1453
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001454 WarningsHandler.emitDiagnostics();
1455}
Alexander Kornienkoab9db512015-06-22 23:07:51 +00001456}} // end namespace clang::consumed