Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/Analysis/Consumed.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- Consumed.cpp -------------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// A intra-procedural analysis for checking consumed properties.  This is based,
10
// in part, on research on linear types.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/Analysis/Analyses/Consumed.h"
15
#include "clang/AST/Attr.h"
16
#include "clang/AST/Decl.h"
17
#include "clang/AST/DeclCXX.h"
18
#include "clang/AST/Expr.h"
19
#include "clang/AST/ExprCXX.h"
20
#include "clang/AST/Stmt.h"
21
#include "clang/AST/StmtVisitor.h"
22
#include "clang/AST/Type.h"
23
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
24
#include "clang/Analysis/AnalysisDeclContext.h"
25
#include "clang/Analysis/CFG.h"
26
#include "clang/Basic/LLVM.h"
27
#include "clang/Basic/OperatorKinds.h"
28
#include "clang/Basic/SourceLocation.h"
29
#include "llvm/ADT/DenseMap.h"
30
#include "llvm/ADT/Optional.h"
31
#include "llvm/ADT/STLExtras.h"
32
#include "llvm/ADT/StringRef.h"
33
#include "llvm/Support/Casting.h"
34
#include "llvm/Support/ErrorHandling.h"
35
#include <cassert>
36
#include <memory>
37
#include <utility>
38
39
// TODO: Adjust states of args to constructors in the same way that arguments to
40
//       function calls are handled.
41
// TODO: Use information from tests in for- and while-loop conditional.
42
// TODO: Add notes about the actual and expected state for
43
// TODO: Correctly identify unreachable blocks when chaining boolean operators.
44
// TODO: Adjust the parser and AttributesList class to support lists of
45
//       identifiers.
46
// TODO: Warn about unreachable code.
47
// TODO: Switch to using a bitmap to track unreachable blocks.
48
// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
49
//       if (valid) ...; (Deferred)
50
// TODO: Take notes on state transitions to provide better warning messages.
51
//       (Deferred)
52
// TODO: Test nested conditionals: A) Checking the same value multiple times,
53
//       and 2) Checking different values. (Deferred)
54
55
using namespace clang;
56
using namespace consumed;
57
58
// Key method definition
59
94
ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() = default;
60
61
4
static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
62
4
  // Find the source location of the first statement in the block, if the block
63
4
  // is not empty.
64
4
  for (const auto &B : *Block)
65
4
    if (Optional<CFGStmt> CS = B.getAs<CFGStmt>())
66
4
      return CS->getStmt()->getBeginLoc();
67
4
68
4
  // Block is empty.
69
4
  // If we have one successor, return the first statement in that block
70
4
  
if (0
Block->succ_size() == 10
&&
*Block->succ_begin()0
)
71
0
    return getFirstStmtLoc(*Block->succ_begin());
72
0
73
0
  return {};
74
0
}
75
76
7
static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
77
7
  // Find the source location of the last statement in the block, if the block
78
7
  // is not empty.
79
7
  if (const Stmt *StmtNode = Block->getTerminatorStmt()) {
80
2
    return StmtNode->getBeginLoc();
81
5
  } else {
82
5
    for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
83
5
         BE = Block->rend(); BI != BE; 
++BI0
) {
84
1
      if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
85
1
        return CS->getStmt()->getBeginLoc();
86
1
    }
87
5
  }
88
7
89
7
  // If we have one successor, return the first statement in that block
90
7
  SourceLocation Loc;
91
4
  if (Block->succ_size() == 1 && *Block->succ_begin())
92
4
    Loc = getFirstStmtLoc(*Block->succ_begin());
93
4
  if (Loc.isValid())
94
4
    return Loc;
95
0
96
0
  // If we have one predecessor, return the last statement in that block
97
0
  if (Block->pred_size() == 1 && *Block->pred_begin())
98
0
    return getLastStmtLoc(*Block->pred_begin());
99
0
100
0
  return Loc;
101
0
}
102
103
54
static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
104
54
  switch (State) {
105
54
  case CS_Unconsumed:
106
38
    return CS_Consumed;
107
54
  case CS_Consumed:
108
15
    return CS_Unconsumed;
109
54
  case CS_None:
110
1
    return CS_None;
111
54
  case CS_Unknown:
112
0
    return CS_Unknown;
113
0
  }
114
0
  llvm_unreachable("invalid enum");
115
0
}
116
117
static bool isCallableInState(const CallableWhenAttr *CWAttr,
118
203
                              ConsumedState State) {
119
270
  for (const auto &S : CWAttr->callableStates()) {
120
270
    ConsumedState MappedAttrState = CS_None;
121
270
122
270
    switch (S) {
123
270
    case CallableWhenAttr::Unknown:
124
76
      MappedAttrState = CS_Unknown;
125
76
      break;
126
270
127
270
    case CallableWhenAttr::Unconsumed:
128
124
      MappedAttrState = CS_Unconsumed;
129
124
      break;
130
270
131
270
    case CallableWhenAttr::Consumed:
132
70
      MappedAttrState = CS_Consumed;
133
70
      break;
134
270
    }
135
270
136
270
    if (MappedAttrState == State)
137
106
      return true;
138
270
  }
139
203
140
203
  
return false97
;
141
203
}
142
143
567
static bool isConsumableType(const QualType &QT) {
144
567
  if (QT->isPointerType() || 
QT->isReferenceType()566
)
145
6
    return false;
146
561
147
561
  if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
148
215
    return RD->hasAttr<ConsumableAttr>();
149
346
150
346
  return false;
151
346
}
152
153
4
static bool isAutoCastType(const QualType &QT) {
154
4
  if (QT->isPointerType() || QT->isReferenceType())
155
0
    return false;
156
4
157
4
  if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
158
4
    return RD->hasAttr<ConsumableAutoCastAttr>();
159
0
160
0
  return false;
161
0
}
162
163
18
static bool isSetOnReadPtrType(const QualType &QT) {
164
18
  if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl())
165
18
    return RD->hasAttr<ConsumableSetOnReadAttr>();
166
0
  return false;
167
0
}
168
169
1
static bool isKnownState(ConsumedState State) {
170
1
  switch (State) {
171
1
  case CS_Unconsumed:
172
1
  case CS_Consumed:
173
1
    return true;
174
1
  case CS_None:
175
0
  case CS_Unknown:
176
0
    return false;
177
0
  }
178
0
  llvm_unreachable("invalid enum");
179
0
}
180
181
48
static bool isRValueRef(QualType ParamType) {
182
48
  return ParamType->isRValueReferenceType();
183
48
}
184
185
187
static bool isTestingFunction(const FunctionDecl *FunDecl) {
186
187
  return FunDecl->hasAttr<TestTypestateAttr>();
187
187
}
188
189
18
static bool isPointerOrRef(QualType ParamType) {
190
18
  return ParamType->isPointerType() || 
ParamType->isReferenceType()15
;
191
18
}
192
193
42
static ConsumedState mapConsumableAttrState(const QualType QT) {
194
42
  assert(isConsumableType(QT));
195
42
196
42
  const ConsumableAttr *CAttr =
197
42
      QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
198
42
199
42
  switch (CAttr->getDefaultState()) {
200
42
  case ConsumableAttr::Unknown:
201
0
    return CS_Unknown;
202
42
  case ConsumableAttr::Unconsumed:
203
42
    return CS_Unconsumed;
204
42
  case ConsumableAttr::Consumed:
205
0
    return CS_Consumed;
206
0
  }
207
0
  llvm_unreachable("invalid enum");
208
0
}
209
210
static ConsumedState
211
9
mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
212
9
  switch (PTAttr->getParamState()) {
213
9
  case ParamTypestateAttr::Unknown:
214
0
    return CS_Unknown;
215
9
  case ParamTypestateAttr::Unconsumed:
216
5
    return CS_Unconsumed;
217
9
  case ParamTypestateAttr::Consumed:
218
4
    return CS_Consumed;
219
0
  }
220
0
  llvm_unreachable("invalid_enum");
221
0
}
222
223
static ConsumedState
224
30
mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
225
30
  switch (RTSAttr->getState()) {
226
30
  case ReturnTypestateAttr::Unknown:
227
0
    return CS_Unknown;
228
30
  case ReturnTypestateAttr::Unconsumed:
229
20
    return CS_Unconsumed;
230
30
  case ReturnTypestateAttr::Consumed:
231
10
    return CS_Consumed;
232
0
  }
233
0
  llvm_unreachable("invalid enum");
234
0
}
235
236
26
static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
237
26
  switch (STAttr->getNewState()) {
238
26
  case SetTypestateAttr::Unknown:
239
0
    return CS_Unknown;
240
26
  case SetTypestateAttr::Unconsumed:
241
1
    return CS_Unconsumed;
242
26
  case SetTypestateAttr::Consumed:
243
25
    return CS_Consumed;
244
0
  }
245
0
  llvm_unreachable("invalid_enum");
246
0
}
247
248
115
static StringRef stateToString(ConsumedState State) {
249
115
  switch (State) {
250
115
  case consumed::CS_None:
251
0
    return "none";
252
115
253
115
  case consumed::CS_Unknown:
254
23
    return "unknown";
255
115
256
115
  case consumed::CS_Unconsumed:
257
23
    return "unconsumed";
258
115
259
115
  case consumed::CS_Consumed:
260
69
    return "consumed";
261
0
  }
262
0
  llvm_unreachable("invalid enum");
263
0
}
264
265
43
static ConsumedState testsFor(const FunctionDecl *FunDecl) {
266
43
  assert(isTestingFunction(FunDecl));
267
43
  switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
268
43
  case TestTypestateAttr::Unconsumed:
269
42
    return CS_Unconsumed;
270
43
  case TestTypestateAttr::Consumed:
271
1
    return CS_Consumed;
272
0
  }
273
0
  llvm_unreachable("invalid enum");
274
0
}
275
276
namespace {
277
278
struct VarTestResult {
279
  const VarDecl *Var;
280
  ConsumedState TestsFor;
281
};
282
283
} // namespace
284
285
namespace clang {
286
namespace consumed {
287
288
enum EffectiveOp {
289
  EO_And,
290
  EO_Or
291
};
292
293
class PropagationInfo {
294
  enum {
295
    IT_None,
296
    IT_State,
297
    IT_VarTest,
298
    IT_BinTest,
299
    IT_Var,
300
    IT_Tmp
301
  } InfoType = IT_None;
302
303
  struct BinTestTy {
304
    const BinaryOperator *Source;
305
    EffectiveOp EOp;
306
    VarTestResult LTest;
307
    VarTestResult RTest;
308
  };
309
310
  union {
311
    ConsumedState State;
312
    VarTestResult VarTest;
313
    const VarDecl *Var;
314
    const CXXBindTemporaryExpr *Tmp;
315
    BinTestTy BinTest;
316
  };
317
318
public:
319
398
  PropagationInfo() = default;
320
  PropagationInfo(const VarTestResult &VarTest)
321
0
      : InfoType(IT_VarTest), VarTest(VarTest) {}
322
323
  PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
324
55
      : InfoType(IT_VarTest) {
325
55
    VarTest.Var      = Var;
326
55
    VarTest.TestsFor = TestsFor;
327
55
  }
328
329
  PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
330
                  const VarTestResult &LTest, const VarTestResult &RTest)
331
4
      : InfoType(IT_BinTest) {
332
4
    BinTest.Source  = Source;
333
4
    BinTest.EOp     = EOp;
334
4
    BinTest.LTest   = LTest;
335
4
    BinTest.RTest   = RTest;
336
4
  }
337
338
  PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
339
                  const VarDecl *LVar, ConsumedState LTestsFor,
340
                  const VarDecl *RVar, ConsumedState RTestsFor)
341
4
      : InfoType(IT_BinTest) {
342
4
    BinTest.Source         = Source;
343
4
    BinTest.EOp            = EOp;
344
4
    BinTest.LTest.Var      = LVar;
345
4
    BinTest.LTest.TestsFor = LTestsFor;
346
4
    BinTest.RTest.Var      = RVar;
347
4
    BinTest.RTest.TestsFor = RTestsFor;
348
4
  }
349
350
  PropagationInfo(ConsumedState State)
351
128
      : InfoType(IT_State), State(State) {}
352
373
  PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
353
  PropagationInfo(const CXXBindTemporaryExpr *Tmp)
354
68
      : InfoType(IT_Tmp), Tmp(Tmp) {}
355
356
0
  const ConsumedState &getState() const {
357
0
    assert(InfoType == IT_State);
358
0
    return State;
359
0
  }
360
361
47
  const VarTestResult &getVarTest() const {
362
47
    assert(InfoType == IT_VarTest);
363
47
    return VarTest;
364
47
  }
365
366
4
  const VarTestResult &getLTest() const {
367
4
    assert(InfoType == IT_BinTest);
368
4
    return BinTest.LTest;
369
4
  }
370
371
4
  const VarTestResult &getRTest() const {
372
4
    assert(InfoType == IT_BinTest);
373
4
    return BinTest.RTest;
374
4
  }
375
376
372
  const VarDecl *getVar() const {
377
372
    assert(InfoType == IT_Var);
378
372
    return Var;
379
372
  }
380
381
32
  const CXXBindTemporaryExpr *getTmp() const {
382
32
    assert(InfoType == IT_Tmp);
383
32
    return Tmp;
384
32
  }
385
386
209
  ConsumedState getAsState(const ConsumedStateMap *StateMap) const {
387
209
    assert(isVar() || isTmp() || isState());
388
209
389
209
    if (isVar())
390
24
      return StateMap->getState(Var);
391
185
    else if (isTmp())
392
61
      return StateMap->getState(Tmp);
393
124
    else if (isState())
394
124
      return State;
395
0
    else
396
0
      return CS_None;
397
209
  }
398
399
7
  EffectiveOp testEffectiveOp() const {
400
7
    assert(InfoType == IT_BinTest);
401
7
    return BinTest.EOp;
402
7
  }
403
404
8
  const BinaryOperator * testSourceNode() const {
405
8
    assert(InfoType == IT_BinTest);
406
8
    return BinTest.Source;
407
8
  }
408
409
34
  bool isValid() const { return InfoType != IT_None; }
410
124
  bool isState() const { return InfoType == IT_State; }
411
62
  bool isVarTest() const { return InfoType == IT_VarTest; }
412
13
  bool isBinTest() const { return InfoType == IT_BinTest; }
413
595
  bool isVar() const { return InfoType == IT_Var; }
414
205
  bool isTmp() const { return InfoType == IT_Tmp; }
415
416
91
  bool isTest() const {
417
91
    return InfoType == IT_VarTest || 
InfoType == IT_BinTest79
;
418
91
  }
419
420
51
  bool isPointerToValue() const {
421
51
    return InfoType == IT_Var || 
InfoType == IT_Tmp29
;
422
51
  }
423
424
16
  PropagationInfo invertTest() const {
425
16
    assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
426
16
427
16
    if (InfoType == IT_VarTest) {
428
12
      return PropagationInfo(VarTest.Var,
429
12
                             invertConsumedUnconsumed(VarTest.TestsFor));
430
12
431
12
    } else 
if (4
InfoType == IT_BinTest4
) {
432
4
      return PropagationInfo(BinTest.Source,
433
4
        BinTest.EOp == EO_And ? 
EO_Or2
:
EO_And2
,
434
4
        BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
435
4
        BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
436
4
    } else {
437
0
      return {};
438
0
    }
439
16
  }
440
};
441
442
} // namespace consumed
443
} // namespace clang
444
445
static void
446
setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
447
73
                    ConsumedState State) {
448
73
  assert(PInfo.isVar() || PInfo.isTmp());
449
73
450
73
  if (PInfo.isVar())
451
44
    StateMap->setState(PInfo.getVar(), State);
452
29
  else
453
29
    StateMap->setState(PInfo.getTmp(), State);
454
73
}
455
456
namespace clang {
457
namespace consumed {
458
459
class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
460
  using MapType = llvm::DenseMap<const Stmt *, PropagationInfo>;
461
  using PairType= std::pair<const Stmt *, PropagationInfo>;
462
  using InfoEntry = MapType::iterator;
463
  using ConstInfoEntry = MapType::const_iterator;
464
465
  ConsumedAnalyzer &Analyzer;
466
  ConsumedStateMap *StateMap;
467
  MapType PropagationMap;
468
469
1.24k
  InfoEntry findInfo(const Expr *E) {
470
1.24k
    if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
471
2
      if (!Cleanups->cleanupsHaveSideEffects())
472
2
        E = Cleanups->getSubExpr();
473
1.24k
    return PropagationMap.find(E->IgnoreParens());
474
1.24k
  }
475
476
65
  ConstInfoEntry findInfo(const Expr *E) const {
477
65
    if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
478
1
      if (!Cleanups->cleanupsHaveSideEffects())
479
0
        E = Cleanups->getSubExpr();
480
65
    return PropagationMap.find(E->IgnoreParens());
481
65
  }
482
483
400
  void insertInfo(const Expr *E, const PropagationInfo &PI) {
484
400
    PropagationMap.insert(PairType(E->IgnoreParens(), PI));
485
400
  }
486
487
  void forwardInfo(const Expr *From, const Expr *To);
488
  void copyInfo(const Expr *From, const Expr *To, ConsumedState CS);
489
  ConsumedState getInfo(const Expr *From);
490
  void setInfo(const Expr *To, ConsumedState NS);
491
  void propagateReturnType(const Expr *Call, const FunctionDecl *Fun);
492
493
public:
494
  void checkCallability(const PropagationInfo &PInfo,
495
                        const FunctionDecl *FunDecl,
496
                        SourceLocation BlameLoc);
497
  bool handleCall(const CallExpr *Call, const Expr *ObjArg,
498
                  const FunctionDecl *FunD);
499
500
  void VisitBinaryOperator(const BinaryOperator *BinOp);
501
  void VisitCallExpr(const CallExpr *Call);
502
  void VisitCastExpr(const CastExpr *Cast);
503
  void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
504
  void VisitCXXConstructExpr(const CXXConstructExpr *Call);
505
  void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
506
  void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
507
  void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
508
  void VisitDeclStmt(const DeclStmt *DelcS);
509
  void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
510
  void VisitMemberExpr(const MemberExpr *MExpr);
511
  void VisitParmVarDecl(const ParmVarDecl *Param);
512
  void VisitReturnStmt(const ReturnStmt *Ret);
513
  void VisitUnaryOperator(const UnaryOperator *UOp);
514
  void VisitVarDecl(const VarDecl *Var);
515
516
  ConsumedStmtVisitor(ConsumedAnalyzer &Analyzer, ConsumedStateMap *StateMap)
517
91
      : Analyzer(Analyzer), StateMap(StateMap) {}
518
519
65
  PropagationInfo getInfo(const Expr *StmtNode) const {
520
65
    ConstInfoEntry Entry = findInfo(StmtNode);
521
65
522
65
    if (Entry != PropagationMap.end())
523
44
      return Entry->second;
524
21
    else
525
21
      return {};
526
65
  }
527
528
377
  void reset(ConsumedStateMap *NewStateMap) {
529
377
    StateMap = NewStateMap;
530
377
  }
531
};
532
533
} // namespace consumed
534
} // namespace clang
535
536
760
void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
537
760
  InfoEntry Entry = findInfo(From);
538
760
  if (Entry != PropagationMap.end())
539
356
    insertInfo(To, Entry->second);
540
760
}
541
542
// Create a new state for To, which is initialized to the state of From.
543
// If NS is not CS_None, sets the state of From to NS.
544
void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
545
45
                                   ConsumedState NS) {
546
45
  InfoEntry Entry = findInfo(From);
547
45
  if (Entry != PropagationMap.end()) {
548
44
    PropagationInfo& PInfo = Entry->second;
549
44
    ConsumedState CS = PInfo.getAsState(StateMap);
550
44
    if (CS != CS_None)
551
44
      insertInfo(To, PropagationInfo(CS));
552
44
    if (NS != CS_None && 
PInfo.isPointerToValue()35
)
553
32
      setStateForVarOrTmp(StateMap, PInfo, NS);
554
44
  }
555
45
}
556
557
// Get the ConsumedState for From
558
18
ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) {
559
18
  InfoEntry Entry = findInfo(From);
560
18
  if (Entry != PropagationMap.end()) {
561
16
    PropagationInfo& PInfo = Entry->second;
562
16
    return PInfo.getAsState(StateMap);
563
16
  }
564
2
  return CS_None;
565
2
}
566
567
// If we already have info for To then update it, otherwise create a new entry.
568
16
void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
569
16
  InfoEntry Entry = findInfo(To);
570
16
  if (Entry != PropagationMap.end()) {
571
16
    PropagationInfo& PInfo = Entry->second;
572
16
    if (PInfo.isPointerToValue())
573
16
      setStateForVarOrTmp(StateMap, PInfo, NS);
574
16
  } else 
if (0
NS != CS_None0
) {
575
0
     insertInfo(To, PropagationInfo(NS));
576
0
  }
577
16
}
578
579
void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
580
                                           const FunctionDecl *FunDecl,
581
285
                                           SourceLocation BlameLoc) {
582
285
  assert(!PInfo.isTest());
583
285
584
285
  const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
585
285
  if (!CWAttr)
586
82
    return;
587
203
588
203
  if (PInfo.isVar()) {
589
168
    ConsumedState VarState = StateMap->getState(PInfo.getVar());
590
168
591
168
    if (VarState == CS_None || isCallableInState(CWAttr, VarState))
592
74
      return;
593
94
594
94
    Analyzer.WarningsHandler.warnUseInInvalidState(
595
94
      FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
596
94
      stateToString(VarState), BlameLoc);
597
94
  } else {
598
35
    ConsumedState TmpState = PInfo.getAsState(StateMap);
599
35
600
35
    if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
601
32
      return;
602
3
603
3
    Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
604
3
      FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
605
3
  }
606
203
}
607
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.
611
bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
612
283
                                     const FunctionDecl *FunD) {
613
283
  unsigned Offset = 0;
614
283
  if (isa<CXXOperatorCallExpr>(Call) && 
isa<CXXMethodDecl>(FunD)145
)
615
144
    Offset = 1;  // first argument is 'this'
616
283
617
283
  // check explicit parameters
618
333
  for (unsigned Index = Offset; Index < Call->getNumArgs(); 
++Index50
) {
619
50
    // Skip variable argument lists.
620
50
    if (Index - Offset >= FunD->getNumParams())
621
0
      break;
622
50
623
50
    const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
624
50
    QualType ParamType = Param->getType();
625
50
626
50
    InfoEntry Entry = findInfo(Call->getArg(Index));
627
50
628
50
    if (Entry == PropagationMap.end() || 
Entry->second.isTest()41
)
629
9
      continue;
630
41
    PropagationInfo PInfo = Entry->second;
631
41
632
41
    // Check that the parameter is in the correct state.
633
41
    if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
634
7
      ConsumedState ParamState = PInfo.getAsState(StateMap);
635
7
      ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
636
7
637
7
      if (ParamState != ExpectedState)
638
6
        Analyzer.WarningsHandler.warnParamTypestateMismatch(
639
6
          Call->getArg(Index)->getExprLoc(),
640
6
          stateToString(ExpectedState), stateToString(ParamState));
641
7
    }
642
41
643
41
    if (!(Entry->second.isVar() || 
Entry->second.isTmp()17
))
644
14
      continue;
645
27
646
27
    // Adjust state on the caller side.
647
27
    if (isRValueRef(ParamType))
648
6
      setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
649
21
    else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
650
3
      setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
651
18
    else if (isPointerOrRef(ParamType) &&
652
18
             (!ParamType->getPointeeType().isConstQualified() ||
653
18
              
isSetOnReadPtrType(ParamType)7
))
654
16
      setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
655
27
  }
656
283
657
283
  if (!ObjArg)
658
66
    return false;
659
217
660
217
  // check implicit 'self' parameter, if present
661
217
  InfoEntry Entry = findInfo(ObjArg);
662
217
  if (Entry != PropagationMap.end()) {
663
213
    PropagationInfo PInfo = Entry->second;
664
213
    checkCallability(PInfo, FunD, Call->getExprLoc());
665
213
666
213
    if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) {
667
26
      if (PInfo.isVar()) {
668
23
        StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
669
23
        return true;
670
23
      }
671
3
      else if (PInfo.isTmp()) {
672
3
        StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
673
3
        return true;
674
3
      }
675
187
    }
676
187
    else if (isTestingFunction(FunD) && 
PInfo.isVar()43
) {
677
43
      PropagationMap.insert(PairType(Call,
678
43
        PropagationInfo(PInfo.getVar(), testsFor(FunD))));
679
43
    }
680
213
  }
681
217
  
return false191
;
682
217
}
683
684
void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
685
265
                                              const FunctionDecl *Fun) {
686
265
  QualType RetType = Fun->getCallResultType();
687
265
  if (RetType->isReferenceType())
688
0
    RetType = RetType->getPointeeType();
689
265
690
265
  if (isConsumableType(RetType)) {
691
36
    ConsumedState ReturnState;
692
36
    if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>())
693
1
      ReturnState = mapReturnTypestateAttrState(RTA);
694
35
    else
695
35
      ReturnState = mapConsumableAttrState(RetType);
696
36
697
36
    PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
698
36
  }
699
265
}
700
701
113
void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
702
113
  switch (BinOp->getOpcode()) {
703
113
  case BO_LAnd:
704
5
  case BO_LOr : {
705
5
    InfoEntry LEntry = findInfo(BinOp->getLHS()),
706
5
              REntry = findInfo(BinOp->getRHS());
707
5
708
5
    VarTestResult LTest, RTest;
709
5
710
5
    if (LEntry != PropagationMap.end() && 
LEntry->second.isVarTest()4
) {
711
4
      LTest = LEntry->second.getVarTest();
712
4
    } else {
713
1
      LTest.Var      = nullptr;
714
1
      LTest.TestsFor = CS_None;
715
1
    }
716
5
717
5
    if (REntry != PropagationMap.end() && 
REntry->second.isVarTest()3
) {
718
3
      RTest = REntry->second.getVarTest();
719
3
    } else {
720
2
      RTest.Var      = nullptr;
721
2
      RTest.TestsFor = CS_None;
722
2
    }
723
5
724
5
    if (!(LTest.Var == nullptr && 
RTest.Var == nullptr1
))
725
4
      PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
726
4
        static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
727
5
    break;
728
5
  }
729
5
730
5
  case BO_PtrMemD:
731
0
  case BO_PtrMemI:
732
0
    forwardInfo(BinOp->getLHS(), BinOp);
733
0
    break;
734
0
735
108
  default:
736
108
    break;
737
113
  }
738
113
}
739
740
67
void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
741
67
  const FunctionDecl *FunDecl = Call->getDirectCallee();
742
67
  if (!FunDecl)
743
0
    return;
744
67
745
67
  // Special case for the std::move function.
746
67
  // TODO: Make this more specific. (Deferred)
747
67
  if (Call->isCallToStdMove()) {
748
1
    copyInfo(Call->getArg(0), Call, CS_Consumed);
749
1
    return;
750
1
  }
751
66
752
66
  handleCall(Call, nullptr, FunDecl);
753
66
  propagateReturnType(Call, FunDecl);
754
66
}
755
756
643
void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
757
643
  forwardInfo(Cast->getSubExpr(), Cast);
758
643
}
759
760
void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
761
35
  const CXXBindTemporaryExpr *Temp) {
762
35
763
35
  InfoEntry Entry = findInfo(Temp->getSubExpr());
764
35
765
35
  if (Entry != PropagationMap.end() && 
!Entry->second.isTest()34
) {
766
34
    StateMap->setState(Temp, Entry->second.getAsState(StateMap));
767
34
    PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
768
34
  }
769
35
}
770
771
96
void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
772
96
  CXXConstructorDecl *Constructor = Call->getConstructor();
773
96
774
96
  QualType ThisType = Constructor->getThisType()->getPointeeType();
775
96
776
96
  if (!isConsumableType(ThisType))
777
4
    return;
778
92
779
92
  // FIXME: What should happen if someone annotates the move constructor?
780
92
  if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
781
23
    // TODO: Adjust state of args appropriately.
782
23
    ConsumedState RetState = mapReturnTypestateAttrState(RTA);
783
23
    PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
784
69
  } else if (Constructor->isDefaultConstructor()) {
785
23
    PropagationMap.insert(PairType(Call,
786
23
      PropagationInfo(consumed::CS_Consumed)));
787
46
  } else if (Constructor->isMoveConstructor()) {
788
33
    copyInfo(Call->getArg(0), Call, CS_Consumed);
789
33
  } else 
if (13
Constructor->isCopyConstructor()13
) {
790
11
    // Copy state from arg.  If setStateOnRead then set arg to CS_Unknown.
791
11
    ConsumedState NS =
792
11
      isSetOnReadPtrType(Constructor->getThisType()) ?
793
9
      
CS_Unknown2
: CS_None;
794
11
    copyInfo(Call->getArg(0), Call, NS);
795
11
  } else {
796
2
    // TODO: Adjust state of args appropriately.
797
2
    ConsumedState RetState = mapConsumableAttrState(ThisType);
798
2
    PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
799
2
  }
800
92
}
801
802
void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
803
72
    const CXXMemberCallExpr *Call) {
804
72
  CXXMethodDecl* MD = Call->getMethodDecl();
805
72
  if (!MD)
806
0
    return;
807
72
808
72
  handleCall(Call, Call->getImplicitObjectArgument(), MD);
809
72
  propagateReturnType(Call, MD);
810
72
}
811
812
void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
813
145
    const CXXOperatorCallExpr *Call) {
814
145
  const auto *FunDecl = dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
815
145
  if (!FunDecl) 
return0
;
816
145
817
145
  if (Call->getOperator() == OO_Equal) {
818
18
    ConsumedState CS = getInfo(Call->getArg(1));
819
18
    if (!handleCall(Call, Call->getArg(0), FunDecl))
820
16
      setInfo(Call->getArg(0), CS);
821
18
    return;
822
18
  }
823
127
824
127
  if (const auto *MCall = dyn_cast<CXXMemberCallExpr>(Call))
825
0
    handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
826
127
  else
827
127
    handleCall(Call, Call->getArg(0), FunDecl);
828
127
829
127
  propagateReturnType(Call, FunDecl);
830
127
}
831
832
584
void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
833
584
  if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
834
372
    if (StateMap->getState(Var) != consumed::CS_None)
835
247
      PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
836
584
}
837
838
88
void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
839
88
  for (const auto *DI : DeclS->decls())
840
88
    if (isa<VarDecl>(DI))
841
88
      VisitVarDecl(cast<VarDecl>(DI));
842
88
843
88
  if (DeclS->isSingleDecl())
844
88
    if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
845
88
      PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
846
88
}
847
848
void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
849
45
  const MaterializeTemporaryExpr *Temp) {
850
45
  forwardInfo(Temp->GetTemporaryExpr(), Temp);
851
45
}
852
853
72
void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
854
72
  forwardInfo(MExpr->getBase(), MExpr);
855
72
}
856
857
26
void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
858
26
  QualType ParamType = Param->getType();
859
26
  ConsumedState ParamState = consumed::CS_None;
860
26
861
26
  if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
862
2
    ParamState = mapParamTypestateAttrState(PTA);
863
24
  else if (isConsumableType(ParamType))
864
3
    ParamState = mapConsumableAttrState(ParamType);
865
21
  else if (isRValueRef(ParamType) &&
866
21
           
isConsumableType(ParamType->getPointeeType())1
)
867
1
    ParamState = mapConsumableAttrState(ParamType->getPointeeType());
868
20
  else if (ParamType->isReferenceType() &&
869
20
           
isConsumableType(ParamType->getPointeeType())4
)
870
3
    ParamState = consumed::CS_Unknown;
871
26
872
26
  if (ParamState != CS_None)
873
9
    StateMap->setState(Param, ParamState);
874
26
}
875
876
14
void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
877
14
  ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
878
14
879
14
  if (ExpectedState != CS_None) {
880
2
    InfoEntry Entry = findInfo(Ret->getRetValue());
881
2
882
2
    if (Entry != PropagationMap.end()) {
883
2
      ConsumedState RetState = Entry->second.getAsState(StateMap);
884
2
885
2
      if (RetState != ExpectedState)
886
1
        Analyzer.WarningsHandler.warnReturnTypestateMismatch(
887
1
          Ret->getReturnLoc(), stateToString(ExpectedState),
888
1
          stateToString(RetState));
889
2
    }
890
2
  }
891
14
892
14
  StateMap->checkParamsForReturnTypestate(Ret->getBeginLoc(),
893
14
                                          Analyzer.WarningsHandler);
894
14
}
895
896
21
void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
897
21
  InfoEntry Entry = findInfo(UOp->getSubExpr());
898
21
  if (Entry == PropagationMap.end()) 
return2
;
899
19
900
19
  switch (UOp->getOpcode()) {
901
19
  case UO_AddrOf:
902
3
    PropagationMap.insert(PairType(UOp, Entry->second));
903
3
    break;
904
19
905
19
  case UO_LNot:
906
16
    if (Entry->second.isTest())
907
16
      PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
908
16
    break;
909
19
910
19
  default:
911
0
    break;
912
19
  }
913
19
}
914
915
// TODO: See if I need to check for reference types here.
916
88
void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
917
88
  if (isConsumableType(Var->getType())) {
918
71
    if (Var->hasInit()) {
919
71
      MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit());
920
71
      if (VIT != PropagationMap.end()) {
921
71
        PropagationInfo PInfo = VIT->second;
922
71
        ConsumedState St = PInfo.getAsState(StateMap);
923
71
924
71
        if (St != consumed::CS_None) {
925
71
          StateMap->setState(Var, St);
926
71
          return;
927
71
        }
928
0
      }
929
71
    }
930
0
    // Otherwise
931
0
    StateMap->setState(Var, consumed::CS_Unknown);
932
0
  }
933
88
}
934
935
static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test,
936
                               ConsumedStateMap *ThenStates,
937
21
                               ConsumedStateMap *ElseStates) {
938
21
  ConsumedState VarState = ThenStates->getState(Test.Var);
939
21
940
21
  if (VarState == CS_Unknown) {
941
8
    ThenStates->setState(Test.Var, Test.TestsFor);
942
8
    ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
943
13
  } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
944
7
    ThenStates->markUnreachable();
945
7
  } else 
if (6
VarState == Test.TestsFor6
) {
946
6
    ElseStates->markUnreachable();
947
6
  }
948
21
}
949
950
static void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
951
                                    ConsumedStateMap *ThenStates,
952
4
                                    ConsumedStateMap *ElseStates) {
953
4
  const VarTestResult &LTest = PInfo.getLTest(),
954
4
                      &RTest = PInfo.getRTest();
955
4
956
4
  ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : 
CS_None0
,
957
4
                RState = RTest.Var ? 
ThenStates->getState(RTest.Var)3
:
CS_None1
;
958
4
959
4
  if (LTest.Var) {
960
4
    if (PInfo.testEffectiveOp() == EO_And) {
961
2
      if (LState == CS_Unknown) {
962
1
        ThenStates->setState(LTest.Var, LTest.TestsFor);
963
1
      } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
964
0
        ThenStates->markUnreachable();
965
1
      } else if (LState == LTest.TestsFor && isKnownState(RState)) {
966
1
        if (RState == RTest.TestsFor)
967
1
          ElseStates->markUnreachable();
968
0
        else
969
0
          ThenStates->markUnreachable();
970
1
      }
971
2
    } else {
972
2
      if (LState == CS_Unknown) {
973
1
        ElseStates->setState(LTest.Var,
974
1
                             invertConsumedUnconsumed(LTest.TestsFor));
975
1
      } else if (LState == LTest.TestsFor) {
976
1
        ElseStates->markUnreachable();
977
1
      } else 
if (0
LState == invertConsumedUnconsumed(LTest.TestsFor)0
&&
978
0
                 isKnownState(RState)) {
979
0
        if (RState == RTest.TestsFor)
980
0
          ElseStates->markUnreachable();
981
0
        else
982
0
          ThenStates->markUnreachable();
983
0
      }
984
2
    }
985
4
  }
986
4
987
4
  if (RTest.Var) {
988
3
    if (PInfo.testEffectiveOp() == EO_And) {
989
2
      if (RState == CS_Unknown)
990
1
        ThenStates->setState(RTest.Var, RTest.TestsFor);
991
1
      else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
992
0
        ThenStates->markUnreachable();
993
2
    } else {
994
1
      if (RState == CS_Unknown)
995
1
        ElseStates->setState(RTest.Var,
996
1
                             invertConsumedUnconsumed(RTest.TestsFor));
997
0
      else if (RState == RTest.TestsFor)
998
0
        ElseStates->markUnreachable();
999
1
    }
1000
3
  }
1001
4
}
1002
1003
bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1004
7
                                            const CFGBlock *TargetBlock) {
1005
7
  assert(CurrBlock && "Block pointer must not be NULL");
1006
7
  assert(TargetBlock && "TargetBlock pointer must not be NULL");
1007
7
1008
7
  unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1009
7
  for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1010
22
       PE = TargetBlock->pred_end(); PI != PE; 
++PI15
) {
1011
16
    if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1012
1
      return false;
1013
16
  }
1014
7
  
return true6
;
1015
7
}
1016
1017
void ConsumedBlockInfo::addInfo(
1018
    const CFGBlock *Block, ConsumedStateMap *StateMap,
1019
89
    std::unique_ptr<ConsumedStateMap> &OwnedStateMap) {
1020
89
  assert(Block && "Block pointer must not be NULL");
1021
89
1022
89
  auto &Entry = StateMapsArray[Block->getBlockID()];
1023
89
1024
89
  if (Entry) {
1025
22
    Entry->intersect(*StateMap);
1026
67
  } else if (OwnedStateMap)
1027
54
    Entry = std::move(OwnedStateMap);
1028
13
  else
1029
13
    Entry = llvm::make_unique<ConsumedStateMap>(*StateMap);
1030
89
}
1031
1032
void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1033
88
                                std::unique_ptr<ConsumedStateMap> StateMap) {
1034
88
  assert(Block && "Block pointer must not be NULL");
1035
88
1036
88
  auto &Entry = StateMapsArray[Block->getBlockID()];
1037
88
1038
88
  if (Entry) {
1039
11
    Entry->intersect(*StateMap);
1040
77
  } else {
1041
77
    Entry = std::move(StateMap);
1042
77
  }
1043
88
}
1044
1045
7
ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1046
7
  assert(Block && "Block pointer must not be NULL");
1047
7
  assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1048
7
1049
7
  return StateMapsArray[Block->getBlockID()].get();
1050
7
}
1051
1052
6
void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1053
6
  StateMapsArray[Block->getBlockID()] = nullptr;
1054
6
}
1055
1056
std::unique_ptr<ConsumedStateMap>
1057
146
ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1058
146
  assert(Block && "Block pointer must not be NULL");
1059
146
1060
146
  auto &Entry = StateMapsArray[Block->getBlockID()];
1061
146
  return isBackEdgeTarget(Block) ? 
llvm::make_unique<ConsumedStateMap>(*Entry)6
1062
146
                                 : 
std::move(Entry)140
;
1063
146
}
1064
1065
96
bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1066
96
  assert(From && "From block must not be NULL");
1067
96
  assert(To   && "From block must not be NULL");
1068
96
1069
96
  return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1070
96
}
1071
1072
146
bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1073
146
  assert(Block && "Block pointer must not be NULL");
1074
146
1075
146
  // Anything with less than two predecessors can't be the target of a back
1076
146
  // edge.
1077
146
  if (Block->pred_size() < 2)
1078
81
    return false;
1079
65
1080
65
  unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1081
65
  for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1082
186
       PE = Block->pred_end(); PI != PE; 
++PI121
) {
1083
127
    if (*PI && 
BlockVisitOrder < VisitOrder[(*PI)->getBlockID()]125
)
1084
6
      return true;
1085
127
  }
1086
65
  
return false59
;
1087
65
}
1088
1089
void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1090
91
  ConsumedWarningsHandlerBase &WarningsHandler) const {
1091
91
1092
91
  for (const auto &DM : VarMap) {
1093
83
    if (isa<ParmVarDecl>(DM.first)) {
1094
10
      const auto *Param = cast<ParmVarDecl>(DM.first);
1095
10
      const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
1096
10
1097
10
      if (!RTA)
1098
8
        continue;
1099
2
1100
2
      ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
1101
2
      if (DM.second != ExpectedState)
1102
2
        WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1103
2
          Param->getNameAsString(), stateToString(ExpectedState),
1104
2
          stateToString(DM.second));
1105
2
    }
1106
83
  }
1107
91
}
1108
1109
0
void ConsumedStateMap::clearTemporaries() {
1110
0
  TmpMap.clear();
1111
0
}
1112
1113
685
ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
1114
685
  VarMapType::const_iterator Entry = VarMap.find(Var);
1115
685
1116
685
  if (Entry != VarMap.end())
1117
559
    return Entry->second;
1118
126
1119
126
  return CS_None;
1120
126
}
1121
1122
ConsumedState
1123
61
ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
1124
61
  TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
1125
61
1126
61
  if (Entry != TmpMap.end())
1127
61
    return Entry->second;
1128
0
1129
0
  return CS_None;
1130
0
}
1131
1132
33
void ConsumedStateMap::intersect(const ConsumedStateMap &Other) {
1133
33
  ConsumedState LocalState;
1134
33
1135
33
  if (this->From && 
this->From == Other.From16
&&
!Other.Reachable10
) {
1136
2
    this->markUnreachable();
1137
2
    return;
1138
2
  }
1139
31
1140
70
  
for (const auto &DM : Other.VarMap)31
{
1141
70
    LocalState = this->getState(DM.first);
1142
70
1143
70
    if (LocalState == CS_None)
1144
1
      continue;
1145
69
1146
69
    if (LocalState != DM.second)
1147
38
     VarMap[DM.first] = CS_Unknown;
1148
69
  }
1149
31
}
1150
1151
void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1152
  const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1153
7
  ConsumedWarningsHandlerBase &WarningsHandler) {
1154
7
1155
7
  ConsumedState LocalState;
1156
7
  SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
1157
7
1158
7
  for (const auto &DM : LoopBackStates->VarMap) {
1159
4
    LocalState = this->getState(DM.first);
1160
4
1161
4
    if (LocalState == CS_None)
1162
0
      continue;
1163
4
1164
4
    if (LocalState != DM.second) {
1165
2
      VarMap[DM.first] = CS_Unknown;
1166
2
      WarningsHandler.warnLoopStateMismatch(BlameLoc,
1167
2
                                            DM.first->getNameAsString());
1168
2
    }
1169
4
  }
1170
7
}
1171
1172
22
void ConsumedStateMap::markUnreachable() {
1173
22
  this->Reachable = false;
1174
22
  VarMap.clear();
1175
22
  TmpMap.clear();
1176
22
}
1177
1178
177
void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1179
177
  VarMap[Var] = State;
1180
177
}
1181
1182
void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
1183
66
                                ConsumedState State) {
1184
66
  TmpMap[Tmp] = State;
1185
66
}
1186
1187
34
void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
1188
34
  TmpMap.erase(Tmp);
1189
34
}
1190
1191
0
bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1192
0
  for (const auto &DM : Other->VarMap)
1193
0
    if (this->getState(DM.first) != DM.second)
1194
0
      return true;
1195
0
  return false;
1196
0
}
1197
1198
void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1199
91
                                                    const FunctionDecl *D) {
1200
91
  QualType ReturnType;
1201
91
  if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1202
0
    ReturnType = Constructor->getThisType()->getPointeeType();
1203
0
  } else
1204
91
    ReturnType = D->getCallResultType();
1205
91
1206
91
  if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
1207
2
    const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1208
2
    if (!RD || 
!RD->hasAttr<ConsumableAttr>()1
) {
1209
1
      // FIXME: This should be removed when template instantiation propagates
1210
1
      //        attributes at template specialization definition, not
1211
1
      //        declaration. When it is removed the test needs to be enabled
1212
1
      //        in SemaDeclAttr.cpp.
1213
1
      WarningsHandler.warnReturnTypestateForUnconsumableType(
1214
1
          RTSAttr->getLocation(), ReturnType.getAsString());
1215
1
      ExpectedReturnState = CS_None;
1216
1
    } else
1217
1
      ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1218
89
  } else if (isConsumableType(ReturnType)) {
1219
4
    if (isAutoCastType(ReturnType))   // We can auto-cast the state to the
1220
3
      ExpectedReturnState = CS_None;  // expected state.
1221
1
    else
1222
1
      ExpectedReturnState = mapConsumableAttrState(ReturnType);
1223
4
  }
1224
85
  else
1225
85
    ExpectedReturnState = CS_None;
1226
91
}
1227
1228
bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1229
377
                                  const ConsumedStmtVisitor &Visitor) {
1230
377
  std::unique_ptr<ConsumedStateMap> FalseStates(
1231
377
      new ConsumedStateMap(*CurrStates));
1232
377
  PropagationInfo PInfo;
1233
377
1234
377
  if (const auto *IfNode =
1235
34
          dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
1236
34
    const Expr *Cond = IfNode->getCond();
1237
34
1238
34
    PInfo = Visitor.getInfo(Cond);
1239
34
    if (!PInfo.isValid() && 
isa<BinaryOperator>(Cond)19
)
1240
10
      PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1241
34
1242
34
    if (PInfo.isVarTest()) {
1243
21
      CurrStates->setSource(Cond);
1244
21
      FalseStates->setSource(Cond);
1245
21
      splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates.get(),
1246
21
                         FalseStates.get());
1247
21
    } else 
if (13
PInfo.isBinTest()13
) {
1248
4
      CurrStates->setSource(PInfo.testSourceNode());
1249
4
      FalseStates->setSource(PInfo.testSourceNode());
1250
4
      splitVarStateForIfBinOp(PInfo, CurrStates.get(), FalseStates.get());
1251
9
    } else {
1252
9
      return false;
1253
9
    }
1254
343
  } else if (const auto *BinOp =
1255
20
       dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1256
20
    PInfo = Visitor.getInfo(BinOp->getLHS());
1257
20
    if (!PInfo.isVarTest()) {
1258
2
      if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1259
1
        PInfo = Visitor.getInfo(BinOp->getRHS());
1260
1
1261
1
        if (!PInfo.isVarTest())
1262
0
          return false;
1263
1
      } else {
1264
1
        return false;
1265
1
      }
1266
19
    }
1267
19
1268
19
    CurrStates->setSource(BinOp);
1269
19
    FalseStates->setSource(BinOp);
1270
19
1271
19
    const VarTestResult &Test = PInfo.getVarTest();
1272
19
    ConsumedState VarState = CurrStates->getState(Test.Var);
1273
19
1274
19
    if (BinOp->getOpcode() == BO_LAnd) {
1275
11
      if (VarState == CS_Unknown)
1276
6
        CurrStates->setState(Test.Var, Test.TestsFor);
1277
5
      else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1278
4
        CurrStates->markUnreachable();
1279
11
1280
11
    } else 
if (8
BinOp->getOpcode() == BO_LOr8
) {
1281
8
      if (VarState == CS_Unknown)
1282
4
        FalseStates->setState(Test.Var,
1283
4
                              invertConsumedUnconsumed(Test.TestsFor));
1284
4
      else if (VarState == Test.TestsFor)
1285
1
        FalseStates->markUnreachable();
1286
8
    }
1287
323
  } else {
1288
323
    return false;
1289
323
  }
1290
44
1291
44
  CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1292
44
1293
44
  if (*SI)
1294
44
    BlockInfo.addInfo(*SI, std::move(CurrStates));
1295
0
  else
1296
0
    CurrStates = nullptr;
1297
44
1298
44
  if (*++SI)
1299
44
    BlockInfo.addInfo(*SI, std::move(FalseStates));
1300
44
1301
44
  return true;
1302
44
}
1303
1304
94
void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1305
94
  const auto *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
1306
94
  if (!D)
1307
3
    return;
1308
91
1309
91
  CFG *CFGraph = AC.getCFG();
1310
91
  if (!CFGraph)
1311
0
    return;
1312
91
1313
91
  determineExpectedReturnState(AC, D);
1314
91
1315
91
  PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1316
91
  // AC.getCFG()->viewCFG(LangOptions());
1317
91
1318
91
  BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
1319
91
1320
91
  CurrStates = llvm::make_unique<ConsumedStateMap>();
1321
91
  ConsumedStmtVisitor Visitor(*this, CurrStates.get());
1322
91
1323
91
  // Add all trackable parameters to the state map.
1324
91
  for (const auto *PI : D->parameters())
1325
26
    Visitor.VisitParmVarDecl(PI);
1326
91
1327
91
  // Visit all of the function's basic blocks.
1328
402
  for (const auto *CurrBlock : *SortedGraph) {
1329
402
    if (!CurrStates)
1330
146
      CurrStates = BlockInfo.getInfo(CurrBlock);
1331
402
1332
402
    if (!CurrStates) {
1333
5
      continue;
1334
397
    } else if (!CurrStates->isReachable()) {
1335
20
      CurrStates = nullptr;
1336
20
      continue;
1337
20
    }
1338
377
1339
377
    Visitor.reset(CurrStates.get());
1340
377
1341
377
    // Visit all of the basic block's statements.
1342
2.18k
    for (const auto &B : *CurrBlock) {
1343
2.18k
      switch (B.getKind()) {
1344
2.18k
      case CFGElement::Statement:
1345
2.11k
        Visitor.Visit(B.castAs<CFGStmt>().getStmt());
1346
2.11k
        break;
1347
2.18k
1348
2.18k
      case CFGElement::TemporaryDtor: {
1349
34
        const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
1350
34
        const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1351
34
1352
34
        Visitor.checkCallability(PropagationInfo(BTE),
1353
34
                                 DTor.getDestructorDecl(AC.getASTContext()),
1354
34
                                 BTE->getExprLoc());
1355
34
        CurrStates->remove(BTE);
1356
34
        break;
1357
2.18k
      }
1358
2.18k
1359
2.18k
      case CFGElement::AutomaticObjectDtor: {
1360
38
        const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
1361
38
        SourceLocation Loc = DTor.getTriggerStmt()->getEndLoc();
1362
38
        const VarDecl *Var = DTor.getVarDecl();
1363
38
1364
38
        Visitor.checkCallability(PropagationInfo(Var),
1365
38
                                 DTor.getDestructorDecl(AC.getASTContext()),
1366
38
                                 Loc);
1367
38
        break;
1368
2.18k
      }
1369
2.18k
1370
2.18k
      default:
1371
0
        break;
1372
2.18k
      }
1373
2.18k
    }
1374
377
1375
377
    // TODO: Handle other forms of branching with precision, including while-
1376
377
    //       and for-loops. (Deferred)
1377
377
    if (!splitState(CurrBlock, Visitor)) {
1378
333
      CurrStates->setSource(nullptr);
1379
333
1380
333
      if (CurrBlock->succ_size() > 1 ||
1381
333
          
(316
CurrBlock->succ_size() == 1316
&&
1382
316
           
(*CurrBlock->succ_begin())->pred_size() > 1228
)) {
1383
83
1384
83
        auto *RawState = CurrStates.get();
1385
83
1386
83
        for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1387
183
             SE = CurrBlock->succ_end(); SI != SE; 
++SI100
) {
1388
100
          if (*SI == nullptr) 
continue4
;
1389
96
1390
96
          if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1391
7
            BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(
1392
7
                *SI, CurrBlock, RawState, WarningsHandler);
1393
7
1394
7
            if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI))
1395
6
              BlockInfo.discardInfo(*SI);
1396
89
          } else {
1397
89
            BlockInfo.addInfo(*SI, RawState, CurrStates);
1398
89
          }
1399
96
        }
1400
83
1401
83
        CurrStates = nullptr;
1402
83
      }
1403
333
    }
1404
377
1405
377
    if (CurrBlock == &AC.getCFG()->getExit() &&
1406
377
        
D->getCallResultType()->isVoidType()88
)
1407
77
      CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1408
77
                                                WarningsHandler);
1409
377
  } // End of block iterator.
1410
91
1411
91
  // Delete the last existing state map.
1412
91
  CurrStates = nullptr;
1413
91
1414
91
  WarningsHandler.emitDiagnostics();
1415
91
}