Coverage Report

Created: 2023-11-11 10:31

/Users/buildslave/jenkins/workspace/coverage/llvm-project/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/STLExtras.h"
31
#include "llvm/ADT/StringRef.h"
32
#include "llvm/Support/Casting.h"
33
#include "llvm/Support/ErrorHandling.h"
34
#include <cassert>
35
#include <memory>
36
#include <optional>
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
98
ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() = default;
60
61
4
static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
62
  // Find the source location of the first statement in the block, if the block
63
  // is not empty.
64
4
  for (const auto &B : *Block)
65
4
    if (std::optional<CFGStmt> CS = B.getAs<CFGStmt>())
66
4
      return CS->getStmt()->getBeginLoc();
67
68
  // Block is empty.
69
  // If we have one successor, return the first statement in that block
70
0
  if (Block->succ_size() == 1 && *Block->succ_begin())
71
0
    return getFirstStmtLoc(*Block->succ_begin());
72
73
0
  return {};
74
0
}
75
76
7
static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
77
  // Find the source location of the last statement in the block, if the block
78
  // 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 (std::optional<CFGStmt> CS = BI->getAs<CFGStmt>())
85
1
        return CS->getStmt()->getBeginLoc();
86
1
    }
87
5
  }
88
89
  // If we have one successor, return the first statement in that block
90
4
  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
96
  // 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
100
0
  return Loc;
101
0
}
102
103
54
static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
104
54
  switch (State) {
105
38
  case CS_Unconsumed:
106
38
    return CS_Consumed;
107
15
  case CS_Consumed:
108
15
    return CS_Unconsumed;
109
1
  case CS_None:
110
1
    return CS_None;
111
0
  case CS_Unknown:
112
0
    return CS_Unknown;
113
54
  }
114
0
  llvm_unreachable("invalid enum");
115
0
}
116
117
static bool isCallableInState(const CallableWhenAttr *CWAttr,
118
208
                              ConsumedState State) {
119
275
  for (const auto &S : CWAttr->callableStates()) {
120
275
    ConsumedState MappedAttrState = CS_None;
121
122
275
    switch (S) {
123
76
    case CallableWhenAttr::Unknown:
124
76
      MappedAttrState = CS_Unknown;
125
76
      break;
126
127
125
    case CallableWhenAttr::Unconsumed:
128
125
      MappedAttrState = CS_Unconsumed;
129
125
      break;
130
131
74
    case CallableWhenAttr::Consumed:
132
74
      MappedAttrState = CS_Consumed;
133
74
      break;
134
275
    }
135
136
275
    if (MappedAttrState == State)
137
110
      return true;
138
275
  }
139
140
98
  return false;
141
208
}
142
143
654
static bool isConsumableType(const QualType &QT) {
144
654
  if (QT->isPointerType() || 
QT->isReferenceType()650
)
145
25
    return false;
146
147
629
  if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
148
268
    return RD->hasAttr<ConsumableAttr>();
149
150
361
  return false;
151
629
}
152
153
4
static bool isAutoCastType(const QualType &QT) {
154
4
  if (QT->isPointerType() || QT->isReferenceType())
155
0
    return false;
156
157
4
  if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
158
4
    return RD->hasAttr<ConsumableAutoCastAttr>();
159
160
0
  return false;
161
4
}
162
163
19
static bool isSetOnReadPtrType(const QualType &QT) {
164
19
  if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl())
165
19
    return RD->hasAttr<ConsumableSetOnReadAttr>();
166
0
  return false;
167
19
}
168
169
1
static bool isKnownState(ConsumedState State) {
170
1
  switch (State) {
171
0
  case CS_Unconsumed:
172
1
  case CS_Consumed:
173
1
    return true;
174
0
  case CS_None:
175
0
  case CS_Unknown:
176
0
    return false;
177
1
  }
178
0
  llvm_unreachable("invalid enum");
179
0
}
180
181
53
static bool isRValueRef(QualType ParamType) {
182
53
  return ParamType->isRValueReferenceType();
183
53
}
184
185
231
static bool isTestingFunction(const FunctionDecl *FunDecl) {
186
231
  return FunDecl->hasAttr<TestTypestateAttr>();
187
231
}
188
189
18
static bool isPointerOrRef(QualType ParamType) {
190
18
  return ParamType->isPointerType() || 
ParamType->isReferenceType()15
;
191
18
}
192
193
43
static ConsumedState mapConsumableAttrState(const QualType QT) {
194
43
  assert(isConsumableType(QT));
195
196
43
  const ConsumableAttr *CAttr =
197
43
      QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
198
199
43
  switch (CAttr->getDefaultState()) {
200
0
  case ConsumableAttr::Unknown:
201
0
    return CS_Unknown;
202
43
  case ConsumableAttr::Unconsumed:
203
43
    return CS_Unconsumed;
204
0
  case ConsumableAttr::Consumed:
205
0
    return CS_Consumed;
206
43
  }
207
0
  llvm_unreachable("invalid enum");
208
0
}
209
210
static ConsumedState
211
9
mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
212
9
  switch (PTAttr->getParamState()) {
213
0
  case ParamTypestateAttr::Unknown:
214
0
    return CS_Unknown;
215
5
  case ParamTypestateAttr::Unconsumed:
216
5
    return CS_Unconsumed;
217
4
  case ParamTypestateAttr::Consumed:
218
4
    return CS_Consumed;
219
9
  }
220
0
  llvm_unreachable("invalid_enum");
221
0
}
222
223
static ConsumedState
224
35
mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
225
35
  switch (RTSAttr->getState()) {
226
0
  case ReturnTypestateAttr::Unknown:
227
0
    return CS_Unknown;
228
25
  case ReturnTypestateAttr::Unconsumed:
229
25
    return CS_Unconsumed;
230
10
  case ReturnTypestateAttr::Consumed:
231
10
    return CS_Consumed;
232
35
  }
233
0
  llvm_unreachable("invalid enum");
234
0
}
235
236
27
static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
237
27
  switch (STAttr->getNewState()) {
238
0
  case SetTypestateAttr::Unknown:
239
0
    return CS_Unknown;
240
2
  case SetTypestateAttr::Unconsumed:
241
2
    return CS_Unconsumed;
242
25
  case SetTypestateAttr::Consumed:
243
25
    return CS_Consumed;
244
27
  }
245
0
  llvm_unreachable("invalid_enum");
246
0
}
247
248
116
static StringRef stateToString(ConsumedState State) {
249
116
  switch (State) {
250
0
  case consumed::CS_None:
251
0
    return "none";
252
253
23
  case consumed::CS_Unknown:
254
23
    return "unknown";
255
256
24
  case consumed::CS_Unconsumed:
257
24
    return "unconsumed";
258
259
69
  case consumed::CS_Consumed:
260
69
    return "consumed";
261
116
  }
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
42
  case TestTypestateAttr::Unconsumed:
269
42
    return CS_Unconsumed;
270
1
  case TestTypestateAttr::Consumed:
271
1
    return CS_Consumed;
272
43
  }
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
416
  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
133
      : InfoType(IT_State), State(State) {}
352
383
  PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
353
  PropagationInfo(const CXXBindTemporaryExpr *Tmp)
354
72
      : 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
379
  const VarDecl *getVar() const {
377
379
    assert(InfoType == IT_Var);
378
379
    return Var;
379
379
  }
380
381
34
  const CXXBindTemporaryExpr *getTmp() const {
382
34
    assert(InfoType == IT_Tmp);
383
34
    return Tmp;
384
34
  }
385
386
218
  ConsumedState getAsState(const ConsumedStateMap *StateMap) const {
387
218
    assert(isVar() || isTmp() || isState());
388
389
218
    if (isVar())
390
27
      return StateMap->getState(Var);
391
191
    else if (isTmp())
392
63
      return StateMap->getState(Tmp);
393
128
    else if (isState())
394
128
      return State;
395
0
    else
396
0
      return CS_None;
397
218
  }
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
256
  bool isState() const { return InfoType == IT_State; }
411
64
  bool isVarTest() const { return InfoType == IT_VarTest; }
412
13
  bool isBinTest() const { return InfoType == IT_BinTest; }
413
915
  bool isVar() const { return InfoType == IT_Var; }
414
436
  bool isTmp() const { return InfoType == IT_Tmp; }
415
416
388
  bool isTest() const {
417
388
    return InfoType == IT_VarTest || 
InfoType == IT_BinTest376
;
418
388
  }
419
420
53
  bool isPointerToValue() const {
421
53
    return InfoType == IT_Var || 
InfoType == IT_Tmp29
;
422
53
  }
423
424
16
  PropagationInfo invertTest() const {
425
16
    assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
426
427
16
    if (InfoType == IT_VarTest) {
428
12
      return PropagationInfo(VarTest.Var,
429
12
                             invertConsumedUnconsumed(VarTest.TestsFor));
430
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
78
                    ConsumedState State) {
448
78
  assert(PInfo.isVar() || PInfo.isTmp());
449
450
78
  if (PInfo.isVar())
451
47
    StateMap->setState(PInfo.getVar(), State);
452
31
  else
453
31
    StateMap->setState(PInfo.getTmp(), State);
454
78
}
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
67
  ConstInfoEntry findInfo(const Expr *E) const {
477
67
    if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
478
1
      if (!Cleanups->cleanupsHaveSideEffects())
479
0
        E = Cleanups->getSubExpr();
480
67
    return PropagationMap.find(E->IgnoreParens());
481
67
  }
482
483
408
  void insertInfo(const Expr *E, const PropagationInfo &PI) {
484
408
    PropagationMap.insert(PairType(E->IgnoreParens(), PI));
485
408
  }
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
95
      : Analyzer(Analyzer), StateMap(StateMap) {}
518
519
67
  PropagationInfo getInfo(const Expr *StmtNode) const {
520
67
    ConstInfoEntry Entry = findInfo(StmtNode);
521
522
67
    if (Entry != PropagationMap.end())
523
44
      return Entry->second;
524
23
    else
525
23
      return {};
526
67
  }
527
528
393
  void reset(ConsumedStateMap *NewStateMap) {
529
393
    StateMap = NewStateMap;
530
393
  }
531
};
532
533
} // namespace consumed
534
} // namespace clang
535
536
743
void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
537
743
  InfoEntry Entry = findInfo(From);
538
743
  if (Entry != PropagationMap.end())
539
361
    insertInfo(To, Entry->second);
540
743
}
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
48
                                   ConsumedState NS) {
546
48
  InfoEntry Entry = findInfo(From);
547
48
  if (Entry != PropagationMap.end()) {
548
47
    PropagationInfo& PInfo = Entry->second;
549
47
    ConsumedState CS = PInfo.getAsState(StateMap);
550
47
    if (CS != CS_None)
551
47
      insertInfo(To, PropagationInfo(CS));
552
47
    if (NS != CS_None && 
PInfo.isPointerToValue()37
)
553
34
      setStateForVarOrTmp(StateMap, PInfo, NS);
554
47
  }
555
48
}
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
18
}
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
291
                                           SourceLocation BlameLoc) {
582
291
  assert(!PInfo.isTest());
583
584
291
  const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
585
291
  if (!CWAttr)
586
83
    return;
587
588
208
  if (PInfo.isVar()) {
589
171
    ConsumedState VarState = StateMap->getState(PInfo.getVar());
590
591
171
    if (VarState == CS_None || isCallableInState(CWAttr, VarState))
592
77
      return;
593
594
94
    Analyzer.WarningsHandler.warnUseInInvalidState(
595
94
      FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
596
94
      stateToString(VarState), BlameLoc);
597
94
  } else {
598
37
    ConsumedState TmpState = PInfo.getAsState(StateMap);
599
600
37
    if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
601
33
      return;
602
603
4
    Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
604
4
      FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
605
4
  }
606
208
}
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
289
                                     const FunctionDecl *FunD) {
613
289
  unsigned Offset = 0;
614
289
  if (isa<CXXOperatorCallExpr>(Call) && 
isa<CXXMethodDecl>(FunD)146
)
615
145
    Offset = 1;  // first argument is 'this'
616
617
  // check explicit parameters
618
343
  for (unsigned Index = Offset; Index < Call->getNumArgs(); 
++Index54
) {
619
    // Skip variable argument lists.
620
54
    if (Index - Offset >= FunD->getNumParams())
621
0
      break;
622
623
54
    const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
624
54
    QualType ParamType = Param->getType();
625
626
54
    InfoEntry Entry = findInfo(Call->getArg(Index));
627
628
54
    if (Entry == PropagationMap.end() || 
Entry->second.isTest()45
)
629
9
      continue;
630
45
    PropagationInfo PInfo = Entry->second;
631
632
    // Check that the parameter is in the correct state.
633
45
    if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
634
7
      ConsumedState ParamState = PInfo.getAsState(StateMap);
635
7
      ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
636
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
643
45
    if (!(Entry->second.isVar() || 
Entry->second.isTmp()20
))
644
15
      continue;
645
646
    // Adjust state on the caller side.
647
30
    if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
648
5
      setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
649
25
    else if (isRValueRef(ParamType) || 
isConsumableType(ParamType)19
)
650
7
      setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
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
30
  }
656
657
289
  if (!ObjArg)
658
70
    return false;
659
660
  // check implicit 'self' parameter, if present
661
219
  InfoEntry Entry = findInfo(ObjArg);
662
219
  if (Entry != PropagationMap.end()) {
663
215
    PropagationInfo PInfo = Entry->second;
664
215
    checkCallability(PInfo, FunD, Call->getExprLoc());
665
666
215
    if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) {
667
27
      if (PInfo.isVar()) {
668
24
        StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
669
24
        return true;
670
24
      }
671
3
      else if (PInfo.isTmp()) {
672
3
        StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
673
3
        return true;
674
3
      }
675
27
    }
676
188
    else if (isTestingFunction(FunD) && 
PInfo.isVar()43
) {
677
43
      PropagationMap.insert(PairType(Call,
678
43
        PropagationInfo(PInfo.getVar(), testsFor(FunD))));
679
43
    }
680
215
  }
681
192
  return false;
682
219
}
683
684
void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
685
271
                                              const FunctionDecl *Fun) {
686
271
  QualType RetType = Fun->getCallResultType();
687
271
  if (RetType->isReferenceType())
688
0
    RetType = RetType->getPointeeType();
689
690
271
  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
697
36
    PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
698
36
  }
699
271
}
700
701
96
void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
702
96
  switch (BinOp->getOpcode()) {
703
3
  case BO_LAnd:
704
7
  case BO_LOr : {
705
7
    InfoEntry LEntry = findInfo(BinOp->getLHS()),
706
7
              REntry = findInfo(BinOp->getRHS());
707
708
7
    VarTestResult LTest, RTest;
709
710
7
    if (LEntry != PropagationMap.end() && 
LEntry->second.isVarTest()4
) {
711
4
      LTest = LEntry->second.getVarTest();
712
4
    } else {
713
3
      LTest.Var      = nullptr;
714
3
      LTest.TestsFor = CS_None;
715
3
    }
716
717
7
    if (REntry != PropagationMap.end() && 
REntry->second.isVarTest()3
) {
718
3
      RTest = REntry->second.getVarTest();
719
4
    } else {
720
4
      RTest.Var      = nullptr;
721
4
      RTest.TestsFor = CS_None;
722
4
    }
723
724
7
    if (!(LTest.Var == nullptr && 
RTest.Var == nullptr3
))
725
4
      PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
726
4
        static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
727
7
    break;
728
3
  }
729
730
0
  case BO_PtrMemD:
731
0
  case BO_PtrMemI:
732
0
    forwardInfo(BinOp->getLHS(), BinOp);
733
0
    break;
734
735
89
  default:
736
89
    break;
737
96
  }
738
96
}
739
740
71
void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
741
71
  const FunctionDecl *FunDecl = Call->getDirectCallee();
742
71
  if (!FunDecl)
743
0
    return;
744
745
  // Special case for the std::move function.
746
  // TODO: Make this more specific. (Deferred)
747
71
  if (Call->isCallToStdMove()) {
748
1
    copyInfo(Call->getArg(0), Call, CS_Consumed);
749
1
    return;
750
1
  }
751
752
70
  handleCall(Call, nullptr, FunDecl);
753
70
  propagateReturnType(Call, FunDecl);
754
70
}
755
756
625
void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
757
625
  forwardInfo(Cast->getSubExpr(), Cast);
758
625
}
759
760
void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
761
37
  const CXXBindTemporaryExpr *Temp) {
762
763
37
  InfoEntry Entry = findInfo(Temp->getSubExpr());
764
765
37
  if (Entry != PropagationMap.end() && 
!Entry->second.isTest()36
) {
766
36
    StateMap->setState(Temp, Entry->second.getAsState(StateMap));
767
36
    PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
768
36
  }
769
37
}
770
771
101
void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
772
101
  CXXConstructorDecl *Constructor = Call->getConstructor();
773
774
101
  QualType ThisType = Constructor->getFunctionObjectParameterType();
775
776
101
  if (!isConsumableType(ThisType))
777
4
    return;
778
779
  // FIXME: What should happen if someone annotates the move constructor?
780
97
  if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
781
    // TODO: Adjust state of args appropriately.
782
25
    ConsumedState RetState = mapReturnTypestateAttrState(RTA);
783
25
    PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
784
72
  } else if (Constructor->isDefaultConstructor()) {
785
23
    PropagationMap.insert(PairType(Call,
786
23
      PropagationInfo(consumed::CS_Consumed)));
787
49
  } else if (Constructor->isMoveConstructor()) {
788
35
    copyInfo(Call->getArg(0), Call, CS_Consumed);
789
35
  } else 
if (14
Constructor->isCopyConstructor()14
) {
790
    // Copy state from arg.  If setStateOnRead then set arg to CS_Unknown.
791
12
    ConsumedState NS =
792
12
      isSetOnReadPtrType(Constructor->getThisType()) ?
793
10
      
CS_Unknown2
: CS_None;
794
12
    copyInfo(Call->getArg(0), Call, NS);
795
12
  } else {
796
    // TODO: Adjust state of args appropriately.
797
2
    ConsumedState RetState = mapConsumableAttrState(ThisType);
798
2
    PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
799
2
  }
800
97
}
801
802
void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
803
73
    const CXXMemberCallExpr *Call) {
804
73
  CXXMethodDecl* MD = Call->getMethodDecl();
805
73
  if (!MD)
806
0
    return;
807
808
73
  handleCall(Call, Call->getImplicitObjectArgument(), MD);
809
73
  propagateReturnType(Call, MD);
810
73
}
811
812
void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
813
146
    const CXXOperatorCallExpr *Call) {
814
146
  const auto *FunDecl = dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
815
146
  if (!FunDecl) 
return0
;
816
817
146
  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
824
128
  if (const auto *MCall = dyn_cast<CXXMemberCallExpr>(Call))
825
0
    handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
826
128
  else
827
128
    handleCall(Call, Call->getArg(0), FunDecl);
828
829
128
  propagateReturnType(Call, FunDecl);
830
128
}
831
832
583
void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
833
583
  if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
834
366
    if (StateMap->getState(Var) != consumed::CS_None)
835
253
      PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
836
583
}
837
838
90
void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
839
90
  for (const auto *DI : DeclS->decls())
840
90
    if (isa<VarDecl>(DI))
841
90
      VisitVarDecl(cast<VarDecl>(DI));
842
843
90
  if (DeclS->isSingleDecl())
844
90
    if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
845
90
      PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
846
90
}
847
848
void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
849
45
  const MaterializeTemporaryExpr *Temp) {
850
45
  forwardInfo(Temp->getSubExpr(), Temp);
851
45
}
852
853
73
void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
854
73
  forwardInfo(MExpr->getBase(), MExpr);
855
73
}
856
857
33
void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
858
33
  QualType ParamType = Param->getType();
859
33
  ConsumedState ParamState = consumed::CS_None;
860
861
33
  if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
862
2
    ParamState = mapParamTypestateAttrState(PTA);
863
31
  else if (isConsumableType(ParamType))
864
3
    ParamState = mapConsumableAttrState(ParamType);
865
28
  else if (isRValueRef(ParamType) &&
866
28
           
isConsumableType(ParamType->getPointeeType())2
)
867
2
    ParamState = mapConsumableAttrState(ParamType->getPointeeType());
868
26
  else if (ParamType->isReferenceType() &&
869
26
           
isConsumableType(ParamType->getPointeeType())4
)
870
3
    ParamState = consumed::CS_Unknown;
871
872
33
  if (ParamState != CS_None)
873
10
    StateMap->setState(Param, ParamState);
874
33
}
875
876
14
void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
877
14
  ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
878
879
14
  if (ExpectedState != CS_None) {
880
2
    InfoEntry Entry = findInfo(Ret->getRetValue());
881
882
2
    if (Entry != PropagationMap.end()) {
883
2
      ConsumedState RetState = Entry->second.getAsState(StateMap);
884
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
892
14
  StateMap->checkParamsForReturnTypestate(Ret->getBeginLoc(),
893
14
                                          Analyzer.WarningsHandler);
894
14
}
895
896
23
void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
897
23
  InfoEntry Entry = findInfo(UOp->getSubExpr());
898
23
  if (Entry == PropagationMap.end()) 
return4
;
899
900
19
  switch (UOp->getOpcode()) {
901
3
  case UO_AddrOf:
902
3
    PropagationMap.insert(PairType(UOp, Entry->second));
903
3
    break;
904
905
16
  case UO_LNot:
906
16
    if (Entry->second.isTest())
907
16
      PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
908
16
    break;
909
910
0
  default:
911
0
    break;
912
19
  }
913
19
}
914
915
// TODO: See if I need to check for reference types here.
916
90
void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
917
90
  if (isConsumableType(Var->getType())) {
918
73
    if (Var->hasInit()) {
919
73
      MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit());
920
73
      if (VIT != PropagationMap.end()) {
921
73
        PropagationInfo PInfo = VIT->second;
922
73
        ConsumedState St = PInfo.getAsState(StateMap);
923
924
73
        if (St != consumed::CS_None) {
925
73
          StateMap->setState(Var, St);
926
73
          return;
927
73
        }
928
73
      }
929
73
    }
930
    // Otherwise
931
0
    StateMap->setState(Var, consumed::CS_Unknown);
932
0
  }
933
90
}
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
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
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
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
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
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
6
  return true;
1015
7
}
1016
1017
void ConsumedBlockInfo::addInfo(
1018
    const CFGBlock *Block, ConsumedStateMap *StateMap,
1019
99
    std::unique_ptr<ConsumedStateMap> &OwnedStateMap) {
1020
99
  assert(Block && "Block pointer must not be NULL");
1021
1022
99
  auto &Entry = StateMapsArray[Block->getBlockID()];
1023
1024
99
  if (Entry) {
1025
25
    Entry->intersect(*StateMap);
1026
74
  } else if (OwnedStateMap)
1027
58
    Entry = std::move(OwnedStateMap);
1028
16
  else
1029
16
    Entry = std::make_unique<ConsumedStateMap>(*StateMap);
1030
99
}
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
1036
88
  auto &Entry = StateMapsArray[Block->getBlockID()];
1037
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
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
153
ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1058
153
  assert(Block && "Block pointer must not be NULL");
1059
1060
153
  auto &Entry = StateMapsArray[Block->getBlockID()];
1061
153
  return isBackEdgeTarget(Block) ? 
std::make_unique<ConsumedStateMap>(*Entry)6
1062
153
                                 : 
std::move(Entry)147
;
1063
153
}
1064
1065
106
bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1066
106
  assert(From && "From block must not be NULL");
1067
106
  assert(To   && "From block must not be NULL");
1068
1069
106
  return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1070
106
}
1071
1072
153
bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1073
153
  assert(Block && "Block pointer must not be NULL");
1074
1075
  // Anything with less than two predecessors can't be the target of a back
1076
  // edge.
1077
153
  if (Block->pred_size() < 2)
1078
85
    return false;
1079
1080
68
  unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1081
68
  for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1082
195
       PE = Block->pred_end(); PI != PE; 
++PI127
) {
1083
133
    if (*PI && 
BlockVisitOrder < VisitOrder[(*PI)->getBlockID()]131
)
1084
6
      return true;
1085
133
  }
1086
62
  return false;
1087
68
}
1088
1089
void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1090
95
  ConsumedWarningsHandlerBase &WarningsHandler) const {
1091
1092
95
  for (const auto &DM : VarMap) {
1093
86
    if (isa<ParmVarDecl>(DM.first)) {
1094
11
      const auto *Param = cast<ParmVarDecl>(DM.first);
1095
11
      const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
1096
1097
11
      if (!RTA)
1098
8
        continue;
1099
1100
3
      ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
1101
3
      if (DM.second != ExpectedState)
1102
2
        WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1103
2
          Param->getNameAsString(), stateToString(ExpectedState),
1104
2
          stateToString(DM.second));
1105
3
    }
1106
86
  }
1107
95
}
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
1116
685
  if (Entry != VarMap.end())
1117
571
    return Entry->second;
1118
1119
114
  return CS_None;
1120
685
}
1121
1122
ConsumedState
1123
63
ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
1124
63
  TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
1125
1126
63
  if (Entry != TmpMap.end())
1127
63
    return Entry->second;
1128
1129
0
  return CS_None;
1130
63
}
1131
1132
36
void ConsumedStateMap::intersect(const ConsumedStateMap &Other) {
1133
36
  ConsumedState LocalState;
1134
1135
36
  if (this->From && 
this->From == Other.From16
&&
!Other.Reachable10
) {
1136
2
    this->markUnreachable();
1137
2
    return;
1138
2
  }
1139
1140
70
  
for (const auto &DM : Other.VarMap)34
{
1141
70
    LocalState = this->getState(DM.first);
1142
1143
70
    if (LocalState == CS_None)
1144
1
      continue;
1145
1146
69
    if (LocalState != DM.second)
1147
38
     VarMap[DM.first] = CS_Unknown;
1148
69
  }
1149
34
}
1150
1151
void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1152
  const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1153
7
  ConsumedWarningsHandlerBase &WarningsHandler) {
1154
1155
7
  ConsumedState LocalState;
1156
7
  SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
1157
1158
7
  for (const auto &DM : LoopBackStates->VarMap) {
1159
4
    LocalState = this->getState(DM.first);
1160
1161
4
    if (LocalState == CS_None)
1162
0
      continue;
1163
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
184
void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1179
184
  VarMap[Var] = State;
1180
184
}
1181
1182
void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
1183
70
                                ConsumedState State) {
1184
70
  TmpMap[Tmp] = State;
1185
70
}
1186
1187
36
void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
1188
36
  TmpMap.erase(Tmp);
1189
36
}
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
95
                                                    const FunctionDecl *D) {
1200
95
  QualType ReturnType;
1201
95
  if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1202
0
    ReturnType = Constructor->getFunctionObjectParameterType();
1203
0
  } else
1204
95
    ReturnType = D->getCallResultType();
1205
1206
95
  if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
1207
2
    const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1208
2
    if (!RD || 
!RD->hasAttr<ConsumableAttr>()1
) {
1209
      // FIXME: This should be removed when template instantiation propagates
1210
      //        attributes at template specialization definition, not
1211
      //        declaration. When it is removed the test needs to be enabled
1212
      //        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
93
  } 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
89
  else
1225
89
    ExpectedReturnState = CS_None;
1226
95
}
1227
1228
bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1229
393
                                  const ConsumedStmtVisitor &Visitor) {
1230
393
  std::unique_ptr<ConsumedStateMap> FalseStates(
1231
393
      new ConsumedStateMap(*CurrStates));
1232
393
  PropagationInfo PInfo;
1233
1234
393
  if (const auto *IfNode =
1235
393
          dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
1236
34
    const Expr *Cond = IfNode->getCond();
1237
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
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
359
  } else if (const auto *BinOp =
1255
359
       dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1256
22
    PInfo = Visitor.getInfo(BinOp->getLHS());
1257
22
    if (!PInfo.isVarTest()) {
1258
4
      if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1259
1
        PInfo = Visitor.getInfo(BinOp->getRHS());
1260
1261
1
        if (!PInfo.isVarTest())
1262
0
          return false;
1263
3
      } else {
1264
3
        return false;
1265
3
      }
1266
4
    }
1267
1268
19
    CurrStates->setSource(BinOp);
1269
19
    FalseStates->setSource(BinOp);
1270
1271
19
    const VarTestResult &Test = PInfo.getVarTest();
1272
19
    ConsumedState VarState = CurrStates->getState(Test.Var);
1273
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
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
337
  } else {
1288
337
    return false;
1289
337
  }
1290
1291
44
  CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1292
1293
44
  if (*SI)
1294
44
    BlockInfo.addInfo(*SI, std::move(CurrStates));
1295
0
  else
1296
0
    CurrStates = nullptr;
1297
1298
44
  if (*++SI)
1299
44
    BlockInfo.addInfo(*SI, std::move(FalseStates));
1300
1301
44
  return true;
1302
393
}
1303
1304
98
void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1305
98
  const auto *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
1306
98
  if (!D)
1307
3
    return;
1308
1309
95
  CFG *CFGraph = AC.getCFG();
1310
95
  if (!CFGraph)
1311
0
    return;
1312
1313
95
  determineExpectedReturnState(AC, D);
1314
1315
95
  PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1316
  // AC.getCFG()->viewCFG(LangOptions());
1317
1318
95
  BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
1319
1320
95
  CurrStates = std::make_unique<ConsumedStateMap>();
1321
95
  ConsumedStmtVisitor Visitor(*this, CurrStates.get());
1322
1323
  // Add all trackable parameters to the state map.
1324
95
  for (const auto *PI : D->parameters())
1325
33
    Visitor.VisitParmVarDecl(PI);
1326
1327
  // Visit all of the function's basic blocks.
1328
418
  for (const auto *CurrBlock : *SortedGraph) {
1329
418
    if (!CurrStates)
1330
153
      CurrStates = BlockInfo.getInfo(CurrBlock);
1331
1332
418
    if (!CurrStates) {
1333
5
      continue;
1334
413
    } else if (!CurrStates->isReachable()) {
1335
20
      CurrStates = nullptr;
1336
20
      continue;
1337
20
    }
1338
1339
393
    Visitor.reset(CurrStates.get());
1340
1341
    // Visit all of the basic block's statements.
1342
2.16k
    for (const auto &B : *CurrBlock) {
1343
2.16k
      switch (B.getKind()) {
1344
2.09k
      case CFGElement::Statement:
1345
2.09k
        Visitor.Visit(B.castAs<CFGStmt>().getStmt());
1346
2.09k
        break;
1347
1348
36
      case CFGElement::TemporaryDtor: {
1349
36
        const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
1350
36
        const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1351
1352
36
        Visitor.checkCallability(PropagationInfo(BTE),
1353
36
                                 DTor.getDestructorDecl(AC.getASTContext()),
1354
36
                                 BTE->getExprLoc());
1355
36
        CurrStates->remove(BTE);
1356
36
        break;
1357
0
      }
1358
1359
40
      case CFGElement::AutomaticObjectDtor: {
1360
40
        const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
1361
40
        SourceLocation Loc = DTor.getTriggerStmt()->getEndLoc();
1362
40
        const VarDecl *Var = DTor.getVarDecl();
1363
1364
40
        Visitor.checkCallability(PropagationInfo(Var),
1365
40
                                 DTor.getDestructorDecl(AC.getASTContext()),
1366
40
                                 Loc);
1367
40
        break;
1368
0
      }
1369
1370
0
      default:
1371
0
        break;
1372
2.16k
      }
1373
2.16k
    }
1374
1375
    // TODO: Handle other forms of branching with precision, including while-
1376
    //       and for-loops. (Deferred)
1377
393
    if (!splitState(CurrBlock, Visitor)) {
1378
349
      CurrStates->setSource(nullptr);
1379
1380
349
      if (CurrBlock->succ_size() > 1 ||
1381
349
          
(329
CurrBlock->succ_size() == 1329
&&
1382
329
           
(*CurrBlock->succ_begin())->pred_size() > 1237
)) {
1383
1384
90
        auto *RawState = CurrStates.get();
1385
1386
90
        for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1387
200
             SE = CurrBlock->succ_end(); SI != SE; 
++SI110
) {
1388
110
          if (*SI == nullptr) 
continue4
;
1389
1390
106
          if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1391
7
            BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(
1392
7
                *SI, CurrBlock, RawState, WarningsHandler);
1393
1394
7
            if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI))
1395
6
              BlockInfo.discardInfo(*SI);
1396
99
          } else {
1397
99
            BlockInfo.addInfo(*SI, RawState, CurrStates);
1398
99
          }
1399
106
        }
1400
1401
90
        CurrStates = nullptr;
1402
90
      }
1403
349
    }
1404
1405
393
    if (CurrBlock == &AC.getCFG()->getExit() &&
1406
393
        
D->getCallResultType()->isVoidType()92
)
1407
81
      CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1408
81
                                                WarningsHandler);
1409
393
  } // End of block iterator.
1410
1411
  // Delete the last existing state map.
1412
95
  CurrStates = nullptr;
1413
1414
95
  WarningsHandler.emitDiagnostics();
1415
95
}