blob: 96edad0c3019fe4ea732bbd8b2c1971bef1efd0c [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"
George Karpenkov50657f62017-09-06 21:45:03 +000025#include "clang/Analysis/AnalysisDeclContext.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000026#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)
Nico Weberb688d132017-09-28 16:16:39 +0000752 if (Call->isCallToStdMove()) {
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000753 copyInfo(Call->getArg(0), Call, CS_Consumed);
754 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000755 }
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000756
Craig Topper25542942014-05-20 04:30:07 +0000757 handleCall(Call, nullptr, FunDecl);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000758 propagateReturnType(Call, FunDecl);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000759}
760
761void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000762 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000763}
764
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000765void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
766 const CXXBindTemporaryExpr *Temp) {
767
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000768 InfoEntry Entry = findInfo(Temp->getSubExpr());
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000769
770 if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
771 StateMap->setState(Temp, Entry->second.getAsState(StateMap));
772 PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
773 }
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000774}
775
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000776void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
777 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Klecknere846dea2013-08-12 23:49:39 +0000778
779 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000780 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
781
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000782 if (!isConsumableType(ThisType))
783 return;
784
785 // FIXME: What should happen if someone annotates the move constructor?
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000786 if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
787 // TODO: Adjust state of args appropriately.
788 ConsumedState RetState = mapReturnTypestateAttrState(RTA);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000789 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
790 } else if (Constructor->isDefaultConstructor()) {
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000791 PropagationMap.insert(PairType(Call,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000792 PropagationInfo(consumed::CS_Consumed)));
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000793 } else if (Constructor->isMoveConstructor()) {
794 copyInfo(Call->getArg(0), Call, CS_Consumed);
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000795 } else if (Constructor->isCopyConstructor()) {
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000796 // Copy state from arg. If setStateOnRead then set arg to CS_Unknown.
797 ConsumedState NS =
798 isSetOnReadPtrType(Constructor->getThisType(CurrContext)) ?
799 CS_Unknown : CS_None;
800 copyInfo(Call->getArg(0), Call, NS);
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000801 } else {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000802 // TODO: Adjust state of args appropriately.
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000803 ConsumedState RetState = mapConsumableAttrState(ThisType);
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000804 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000805 }
806}
807
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000808
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000809void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000810 const CXXMemberCallExpr *Call) {
811 CXXMethodDecl* MD = Call->getMethodDecl();
812 if (!MD)
813 return;
814
815 handleCall(Call, Call->getImplicitObjectArgument(), MD);
816 propagateReturnType(Call, MD);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000817}
818
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000819
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000820void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000821 const CXXOperatorCallExpr *Call) {
822
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000823 const FunctionDecl *FunDecl =
824 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000825 if (!FunDecl) return;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000826
827 if (Call->getOperator() == OO_Equal) {
828 ConsumedState CS = getInfo(Call->getArg(1));
829 if (!handleCall(Call, Call->getArg(0), FunDecl))
830 setInfo(Call->getArg(0), CS);
831 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000832 }
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000833
834 if (const CXXMemberCallExpr *MCall = dyn_cast<CXXMemberCallExpr>(Call))
835 handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
836 else
837 handleCall(Call, Call->getArg(0), FunDecl);
838
839 propagateReturnType(Call, FunDecl);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000840}
841
842void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
843 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
844 if (StateMap->getState(Var) != consumed::CS_None)
845 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
846}
847
848void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
Aaron Ballman535bbcc2014-03-14 17:01:24 +0000849 for (const auto *DI : DeclS->decls())
850 if (isa<VarDecl>(DI))
851 VisitVarDecl(cast<VarDecl>(DI));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000852
853 if (DeclS->isSingleDecl())
854 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
855 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
856}
857
858void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
859 const MaterializeTemporaryExpr *Temp) {
860
Chris Wailes44930882013-10-24 14:28:17 +0000861 forwardInfo(Temp->GetTemporaryExpr(), Temp);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000862}
863
864void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
865 forwardInfo(MExpr->getBase(), MExpr);
866}
867
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000868
869void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikie16f76d22013-09-06 01:28:43 +0000870 QualType ParamType = Param->getType();
871 ConsumedState ParamState = consumed::CS_None;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000872
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000873 if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
874 ParamState = mapParamTypestateAttrState(PTA);
875 else if (isConsumableType(ParamType))
876 ParamState = mapConsumableAttrState(ParamType);
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000877 else if (isRValueRef(ParamType) &&
878 isConsumableType(ParamType->getPointeeType()))
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000879 ParamState = mapConsumableAttrState(ParamType->getPointeeType());
880 else if (ParamType->isReferenceType() &&
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000881 isConsumableType(ParamType->getPointeeType()))
David Blaikie16f76d22013-09-06 01:28:43 +0000882 ParamState = consumed::CS_Unknown;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000883
884 if (ParamState != CS_None)
David Blaikie16f76d22013-09-06 01:28:43 +0000885 StateMap->setState(Param, ParamState);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000886}
887
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000888void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000889 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
890
891 if (ExpectedState != CS_None) {
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000892 InfoEntry Entry = findInfo(Ret->getRetValue());
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000893
894 if (Entry != PropagationMap.end()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000895 ConsumedState RetState = Entry->second.getAsState(StateMap);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000896
897 if (RetState != ExpectedState)
898 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
899 Ret->getReturnLoc(), stateToString(ExpectedState),
900 stateToString(RetState));
901 }
902 }
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000903
904 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
905 Analyzer.WarningsHandler);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000906}
907
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000908void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000909 InfoEntry Entry = findInfo(UOp->getSubExpr());
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000910 if (Entry == PropagationMap.end()) return;
911
912 switch (UOp->getOpcode()) {
913 case UO_AddrOf:
914 PropagationMap.insert(PairType(UOp, Entry->second));
915 break;
916
917 case UO_LNot:
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000918 if (Entry->second.isTest())
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000919 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
920 break;
921
922 default:
923 break;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000924 }
925}
926
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000927// TODO: See if I need to check for reference types here.
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000928void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000929 if (isConsumableType(Var->getType())) {
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000930 if (Var->hasInit()) {
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +0000931 MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit());
DeLesley Hutchins81218662013-10-18 23:11:49 +0000932 if (VIT != PropagationMap.end()) {
933 PropagationInfo PInfo = VIT->second;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000934 ConsumedState St = PInfo.getAsState(StateMap);
935
DeLesley Hutchins81218662013-10-18 23:11:49 +0000936 if (St != consumed::CS_None) {
937 StateMap->setState(Var, St);
938 return;
939 }
940 }
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000941 }
DeLesley Hutchins81218662013-10-18 23:11:49 +0000942 // Otherwise
943 StateMap->setState(Var, consumed::CS_Unknown);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000944 }
945}
Alexander Kornienkoab9db512015-06-22 23:07:51 +0000946}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000947
948namespace clang {
949namespace consumed {
950
Benjamin Kramer3a743452015-03-09 15:03:32 +0000951static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test,
952 ConsumedStateMap *ThenStates,
953 ConsumedStateMap *ElseStates) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000954 ConsumedState VarState = ThenStates->getState(Test.Var);
955
956 if (VarState == CS_Unknown) {
957 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000958 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000959
960 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
961 ThenStates->markUnreachable();
962
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000963 } else if (VarState == Test.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000964 ElseStates->markUnreachable();
965 }
966}
967
Benjamin Kramer3a743452015-03-09 15:03:32 +0000968static void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
969 ConsumedStateMap *ThenStates,
970 ConsumedStateMap *ElseStates) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000971 const VarTestResult &LTest = PInfo.getLTest(),
972 &RTest = PInfo.getRTest();
973
974 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
975 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
976
977 if (LTest.Var) {
978 if (PInfo.testEffectiveOp() == EO_And) {
979 if (LState == CS_Unknown) {
980 ThenStates->setState(LTest.Var, LTest.TestsFor);
981
982 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
983 ThenStates->markUnreachable();
984
985 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000986 if (RState == RTest.TestsFor)
987 ElseStates->markUnreachable();
988 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000989 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000990 }
991
992 } else {
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000993 if (LState == CS_Unknown) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000994 ElseStates->setState(LTest.Var,
995 invertConsumedUnconsumed(LTest.TestsFor));
996
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000997 } else if (LState == LTest.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000998 ElseStates->markUnreachable();
999
1000 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
1001 isKnownState(RState)) {
1002
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001003 if (RState == RTest.TestsFor)
1004 ElseStates->markUnreachable();
1005 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001006 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001007 }
1008 }
1009 }
1010
1011 if (RTest.Var) {
1012 if (PInfo.testEffectiveOp() == EO_And) {
1013 if (RState == CS_Unknown)
1014 ThenStates->setState(RTest.Var, RTest.TestsFor);
1015 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
1016 ThenStates->markUnreachable();
1017
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001018 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001019 if (RState == CS_Unknown)
1020 ElseStates->setState(RTest.Var,
1021 invertConsumedUnconsumed(RTest.TestsFor));
1022 else if (RState == RTest.TestsFor)
1023 ElseStates->markUnreachable();
1024 }
1025 }
1026}
1027
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001028bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1029 const CFGBlock *TargetBlock) {
1030
1031 assert(CurrBlock && "Block pointer must not be NULL");
1032 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1033
1034 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1035 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1036 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1037 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1038 return false;
1039 }
1040 return true;
1041}
1042
David Blaikie86d8cf32015-08-14 01:26:19 +00001043void ConsumedBlockInfo::addInfo(
1044 const CFGBlock *Block, ConsumedStateMap *StateMap,
1045 std::unique_ptr<ConsumedStateMap> &OwnedStateMap) {
1046
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001047 assert(Block && "Block pointer must not be NULL");
David Blaikie86d8cf32015-08-14 01:26:19 +00001048
1049 auto &Entry = StateMapsArray[Block->getBlockID()];
1050
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001051 if (Entry) {
David Blaikie86d8cf32015-08-14 01:26:19 +00001052 Entry->intersect(*StateMap);
1053 } else if (OwnedStateMap)
1054 Entry = std::move(OwnedStateMap);
1055 else
1056 Entry = llvm::make_unique<ConsumedStateMap>(*StateMap);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001057}
1058
1059void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
David Blaikie86d8cf32015-08-14 01:26:19 +00001060 std::unique_ptr<ConsumedStateMap> StateMap) {
Craig Topper25542942014-05-20 04:30:07 +00001061
1062 assert(Block && "Block pointer must not be NULL");
1063
David Blaikie86d8cf32015-08-14 01:26:19 +00001064 auto &Entry = StateMapsArray[Block->getBlockID()];
1065
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001066 if (Entry) {
David Blaikie86d8cf32015-08-14 01:26:19 +00001067 Entry->intersect(*StateMap);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001068 } else {
David Blaikie86d8cf32015-08-14 01:26:19 +00001069 Entry = std::move(StateMap);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001070 }
1071}
1072
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001073ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1074 assert(Block && "Block pointer must not be NULL");
1075 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
David Blaikie86d8cf32015-08-14 01:26:19 +00001076
1077 return StateMapsArray[Block->getBlockID()].get();
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001078}
1079
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001080void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
David Blaikie86d8cf32015-08-14 01:26:19 +00001081 StateMapsArray[Block->getBlockID()] = nullptr;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001082}
1083
David Blaikie86d8cf32015-08-14 01:26:19 +00001084std::unique_ptr<ConsumedStateMap>
1085ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001086 assert(Block && "Block pointer must not be NULL");
David Blaikie86d8cf32015-08-14 01:26:19 +00001087
1088 auto &Entry = StateMapsArray[Block->getBlockID()];
1089 return isBackEdgeTarget(Block) ? llvm::make_unique<ConsumedStateMap>(*Entry)
1090 : std::move(Entry);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001091}
1092
1093bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1094 assert(From && "From block must not be NULL");
1095 assert(To && "From block must not be NULL");
1096
1097 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1098}
1099
1100bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
Craig Topper25542942014-05-20 04:30:07 +00001101 assert(Block && "Block pointer must not be NULL");
1102
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001103 // Anything with less than two predecessors can't be the target of a back
1104 // edge.
1105 if (Block->pred_size() < 2)
1106 return false;
1107
1108 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1109 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1110 PE = Block->pred_end(); PI != PE; ++PI) {
1111 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1112 return true;
1113 }
1114 return false;
1115}
1116
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001117void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1118 ConsumedWarningsHandlerBase &WarningsHandler) const {
1119
Aaron Ballman35897d92014-04-28 14:56:59 +00001120 for (const auto &DM : VarMap) {
1121 if (isa<ParmVarDecl>(DM.first)) {
1122 const ParmVarDecl *Param = cast<ParmVarDecl>(DM.first);
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001123 const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001124
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001125 if (!RTA)
1126 continue;
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001127
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001128 ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
Aaron Ballman35897d92014-04-28 14:56:59 +00001129 if (DM.second != ExpectedState)
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001130 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1131 Param->getNameAsString(), stateToString(ExpectedState),
Aaron Ballman35897d92014-04-28 14:56:59 +00001132 stateToString(DM.second));
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001133 }
1134 }
1135}
1136
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001137void ConsumedStateMap::clearTemporaries() {
1138 TmpMap.clear();
1139}
1140
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001141ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001142 VarMapType::const_iterator Entry = VarMap.find(Var);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001143
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001144 if (Entry != VarMap.end())
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001145 return Entry->second;
1146
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001147 return CS_None;
1148}
1149
1150ConsumedState
1151ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
1152 TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
1153
1154 if (Entry != TmpMap.end())
1155 return Entry->second;
1156
1157 return CS_None;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001158}
1159
David Blaikie86d8cf32015-08-14 01:26:19 +00001160void ConsumedStateMap::intersect(const ConsumedStateMap &Other) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001161 ConsumedState LocalState;
David Blaikie86d8cf32015-08-14 01:26:19 +00001162
1163 if (this->From && this->From == Other.From && !Other.Reachable) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001164 this->markUnreachable();
1165 return;
1166 }
David Blaikie86d8cf32015-08-14 01:26:19 +00001167
1168 for (const auto &DM : Other.VarMap) {
Aaron Ballman35897d92014-04-28 14:56:59 +00001169 LocalState = this->getState(DM.first);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001170
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001171 if (LocalState == CS_None)
1172 continue;
1173
Aaron Ballman35897d92014-04-28 14:56:59 +00001174 if (LocalState != DM.second)
1175 VarMap[DM.first] = CS_Unknown;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001176 }
1177}
1178
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001179void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1180 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1181 ConsumedWarningsHandlerBase &WarningsHandler) {
1182
1183 ConsumedState LocalState;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001184 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001185
Aaron Ballman35897d92014-04-28 14:56:59 +00001186 for (const auto &DM : LoopBackStates->VarMap) {
1187 LocalState = this->getState(DM.first);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001188
1189 if (LocalState == CS_None)
1190 continue;
1191
Aaron Ballman35897d92014-04-28 14:56:59 +00001192 if (LocalState != DM.second) {
1193 VarMap[DM.first] = CS_Unknown;
Aaron Ballmanfe46e622014-04-28 13:01:32 +00001194 WarningsHandler.warnLoopStateMismatch(BlameLoc,
Aaron Ballman35897d92014-04-28 14:56:59 +00001195 DM.first->getNameAsString());
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001196 }
1197 }
1198}
1199
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001200void ConsumedStateMap::markUnreachable() {
1201 this->Reachable = false;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001202 VarMap.clear();
1203 TmpMap.clear();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001204}
1205
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001206void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001207 VarMap[Var] = State;
1208}
1209
1210void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
1211 ConsumedState State) {
1212 TmpMap[Tmp] = State;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001213}
1214
Manuel Klimekb33bded2014-05-08 11:50:00 +00001215void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
1216 TmpMap.erase(Tmp);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001217}
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001218
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001219bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
Aaron Ballman35897d92014-04-28 14:56:59 +00001220 for (const auto &DM : Other->VarMap)
1221 if (this->getState(DM.first) != DM.second)
Aaron Ballmanfe46e622014-04-28 13:01:32 +00001222 return true;
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001223 return false;
1224}
1225
David Blaikie16f76d22013-09-06 01:28:43 +00001226void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1227 const FunctionDecl *D) {
1228 QualType ReturnType;
1229 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1230 ASTContext &CurrContext = AC.getASTContext();
1231 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1232 } else
1233 ReturnType = D->getCallResultType();
1234
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001235 if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
David Blaikie16f76d22013-09-06 01:28:43 +00001236 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1237 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1238 // FIXME: This should be removed when template instantiation propagates
1239 // attributes at template specialization definition, not
1240 // declaration. When it is removed the test needs to be enabled
1241 // in SemaDeclAttr.cpp.
1242 WarningsHandler.warnReturnTypestateForUnconsumableType(
1243 RTSAttr->getLocation(), ReturnType.getAsString());
1244 ExpectedReturnState = CS_None;
1245 } else
1246 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +00001247 } else if (isConsumableType(ReturnType)) {
1248 if (isAutoCastType(ReturnType)) // We can auto-cast the state to the
1249 ExpectedReturnState = CS_None; // expected state.
1250 else
1251 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1252 }
David Blaikie16f76d22013-09-06 01:28:43 +00001253 else
1254 ExpectedReturnState = CS_None;
1255}
1256
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001257bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1258 const ConsumedStmtVisitor &Visitor) {
Ahmed Charlesb8984322014-03-07 20:03:18 +00001259
1260 std::unique_ptr<ConsumedStateMap> FalseStates(
1261 new ConsumedStateMap(*CurrStates));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001262 PropagationInfo PInfo;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001263
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001264 if (const IfStmt *IfNode =
1265 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001266
DeLesley Hutchinsd7fa5bd2014-03-20 20:39:20 +00001267 const Expr *Cond = IfNode->getCond();
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001268
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001269 PInfo = Visitor.getInfo(Cond);
1270 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1271 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1272
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001273 if (PInfo.isVarTest()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001274 CurrStates->setSource(Cond);
1275 FalseStates->setSource(Cond);
David Blaikie86d8cf32015-08-14 01:26:19 +00001276 splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates.get(),
Chris Wailes2dc8c422013-10-25 15:33:28 +00001277 FalseStates.get());
David Blaikie86d8cf32015-08-14 01:26:19 +00001278
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001279 } else if (PInfo.isBinTest()) {
1280 CurrStates->setSource(PInfo.testSourceNode());
1281 FalseStates->setSource(PInfo.testSourceNode());
David Blaikie86d8cf32015-08-14 01:26:19 +00001282 splitVarStateForIfBinOp(PInfo, CurrStates.get(), FalseStates.get());
1283
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001284 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001285 return false;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001286 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001287
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001288 } else if (const BinaryOperator *BinOp =
1289 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1290
1291 PInfo = Visitor.getInfo(BinOp->getLHS());
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001292 if (!PInfo.isVarTest()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001293 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1294 PInfo = Visitor.getInfo(BinOp->getRHS());
1295
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001296 if (!PInfo.isVarTest())
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001297 return false;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001298
1299 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001300 return false;
1301 }
1302 }
1303
1304 CurrStates->setSource(BinOp);
1305 FalseStates->setSource(BinOp);
1306
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001307 const VarTestResult &Test = PInfo.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001308 ConsumedState VarState = CurrStates->getState(Test.Var);
1309
1310 if (BinOp->getOpcode() == BO_LAnd) {
1311 if (VarState == CS_Unknown)
1312 CurrStates->setState(Test.Var, Test.TestsFor);
1313 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1314 CurrStates->markUnreachable();
1315
1316 } else if (BinOp->getOpcode() == BO_LOr) {
1317 if (VarState == CS_Unknown)
1318 FalseStates->setState(Test.Var,
1319 invertConsumedUnconsumed(Test.TestsFor));
1320 else if (VarState == Test.TestsFor)
1321 FalseStates->markUnreachable();
1322 }
1323
1324 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001325 return false;
1326 }
1327
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001328 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1329
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001330 if (*SI)
David Blaikie86d8cf32015-08-14 01:26:19 +00001331 BlockInfo.addInfo(*SI, std::move(CurrStates));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001332 else
David Blaikie86d8cf32015-08-14 01:26:19 +00001333 CurrStates = nullptr;
Ahmed Charles9a16beb2014-03-07 19:33:25 +00001334
David Blaikie86d8cf32015-08-14 01:26:19 +00001335 if (*++SI)
1336 BlockInfo.addInfo(*SI, std::move(FalseStates));
1337
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001338 return true;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001339}
1340
1341void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1342 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001343 if (!D)
1344 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001345
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001346 CFG *CFGraph = AC.getCFG();
1347 if (!CFGraph)
1348 return;
DeLesley Hutchins65013202013-10-17 18:19:31 +00001349
David Blaikie16f76d22013-09-06 01:28:43 +00001350 determineExpectedReturnState(AC, D);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001351
Artyom Skrobov27720762014-09-23 08:34:41 +00001352 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001353 // AC.getCFG()->viewCFG(LangOptions());
1354
1355 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
David Blaikie86d8cf32015-08-14 01:26:19 +00001356
1357 CurrStates = llvm::make_unique<ConsumedStateMap>();
1358 ConsumedStmtVisitor Visitor(AC, *this, CurrStates.get());
1359
DeLesley Hutchinsb570c132013-08-29 22:36:05 +00001360 // Add all trackable parameters to the state map.
David Majnemer59f77922016-06-24 04:05:48 +00001361 for (const auto *PI : D->parameters())
Aaron Ballmanf6bf62e2014-03-07 15:12:56 +00001362 Visitor.VisitParmVarDecl(PI);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001363
1364 // Visit all of the function's basic blocks.
Aaron Ballmanfe46e622014-04-28 13:01:32 +00001365 for (const auto *CurrBlock : *SortedGraph) {
Craig Topper25542942014-05-20 04:30:07 +00001366 if (!CurrStates)
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001367 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001368
1369 if (!CurrStates) {
1370 continue;
1371
1372 } else if (!CurrStates->isReachable()) {
Craig Topper25542942014-05-20 04:30:07 +00001373 CurrStates = nullptr;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001374 continue;
1375 }
David Blaikie86d8cf32015-08-14 01:26:19 +00001376
1377 Visitor.reset(CurrStates.get());
1378
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001379 // Visit all of the basic block's statements.
Aaron Ballman35897d92014-04-28 14:56:59 +00001380 for (const auto &B : *CurrBlock) {
1381 switch (B.getKind()) {
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001382 case CFGElement::Statement:
Aaron Ballman35897d92014-04-28 14:56:59 +00001383 Visitor.Visit(B.castAs<CFGStmt>().getStmt());
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001384 break;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001385
1386 case CFGElement::TemporaryDtor: {
Aaron Ballman35897d92014-04-28 14:56:59 +00001387 const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001388 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001389
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001390 Visitor.checkCallability(PropagationInfo(BTE),
1391 DTor.getDestructorDecl(AC.getASTContext()),
1392 BTE->getExprLoc());
Manuel Klimekb33bded2014-05-08 11:50:00 +00001393 CurrStates->remove(BTE);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001394 break;
1395 }
1396
1397 case CFGElement::AutomaticObjectDtor: {
Aaron Ballman35897d92014-04-28 14:56:59 +00001398 const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001399 SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001400 const VarDecl *Var = DTor.getVarDecl();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001401
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001402 Visitor.checkCallability(PropagationInfo(Var),
1403 DTor.getDestructorDecl(AC.getASTContext()),
1404 Loc);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001405 break;
1406 }
1407
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001408 default:
1409 break;
1410 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001411 }
1412
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001413 // TODO: Handle other forms of branching with precision, including while-
1414 // and for-loops. (Deferred)
1415 if (!splitState(CurrBlock, Visitor)) {
Craig Topper25542942014-05-20 04:30:07 +00001416 CurrStates->setSource(nullptr);
1417
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001418 if (CurrBlock->succ_size() > 1 ||
1419 (CurrBlock->succ_size() == 1 &&
1420 (*CurrBlock->succ_begin())->pred_size() > 1)) {
David Blaikie86d8cf32015-08-14 01:26:19 +00001421
1422 auto *RawState = CurrStates.get();
1423
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001424 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1425 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
Craig Topper25542942014-05-20 04:30:07 +00001426
1427 if (*SI == nullptr) continue;
1428
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001429 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
David Blaikie86d8cf32015-08-14 01:26:19 +00001430 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(
1431 *SI, CurrBlock, RawState, WarningsHandler);
1432
DeLesley Hutchins773ba372015-04-15 22:32:44 +00001433 if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI))
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001434 BlockInfo.discardInfo(*SI);
1435 } else {
David Blaikie86d8cf32015-08-14 01:26:19 +00001436 BlockInfo.addInfo(*SI, RawState, CurrStates);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001437 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001438 }
Craig Topper25542942014-05-20 04:30:07 +00001439
1440 CurrStates = nullptr;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001441 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001442 }
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001443
1444 if (CurrBlock == &AC.getCFG()->getExit() &&
1445 D->getCallResultType()->isVoidType())
1446 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1447 WarningsHandler);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001448 } // End of block iterator.
1449
1450 // Delete the last existing state map.
David Blaikie86d8cf32015-08-14 01:26:19 +00001451 CurrStates = nullptr;
1452
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001453 WarningsHandler.emitDiagnostics();
1454}
Alexander Kornienkoab9db512015-06-22 23:07:51 +00001455}} // end namespace clang::consumed