Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Analysis/FlowSensitive/Transfer.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- Transfer.cpp --------------------------------------------*- C++ -*-===//
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
//  This file defines transfer functions that evaluate program statements and
10
//  update an environment accordingly.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/Analysis/FlowSensitive/Transfer.h"
15
#include "clang/AST/Decl.h"
16
#include "clang/AST/DeclBase.h"
17
#include "clang/AST/DeclCXX.h"
18
#include "clang/AST/Expr.h"
19
#include "clang/AST/ExprCXX.h"
20
#include "clang/AST/OperationKinds.h"
21
#include "clang/AST/Stmt.h"
22
#include "clang/AST/StmtVisitor.h"
23
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
24
#include "clang/Basic/OperatorKinds.h"
25
#include "llvm/Support/Casting.h"
26
#include <cassert>
27
#include <memory>
28
29
namespace clang {
30
namespace dataflow {
31
32
106
static const Expr *skipExprWithCleanups(const Expr *E) {
33
106
  if (auto *C = dyn_cast_or_null<ExprWithCleanups>(E))
34
14
    return C->getSubExpr();
35
92
  return E;
36
106
}
37
38
class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
39
public:
40
22.7k
  TransferVisitor(Environment &Env) : Env(Env) {}
41
42
68
  void VisitBinaryOperator(const BinaryOperator *S) {
43
68
    if (S->getOpcode() == BO_Assign) {
44
      // The CFG does not contain `ParenExpr` as top-level statements in basic
45
      // blocks, however sub-expressions can still be of that type.
46
60
      assert(S->getLHS() != nullptr);
47
0
      const Expr *LHS = S->getLHS()->IgnoreParens();
48
49
60
      assert(LHS != nullptr);
50
0
      auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference);
51
60
      if (LHSLoc == nullptr)
52
0
        return;
53
54
      // The CFG does not contain `ParenExpr` as top-level statements in basic
55
      // blocks, however sub-expressions can still be of that type.
56
60
      assert(S->getRHS() != nullptr);
57
0
      const Expr *RHS = S->getRHS()->IgnoreParens();
58
59
60
      assert(RHS != nullptr);
60
0
      Value *RHSVal = Env.getValue(*RHS, SkipPast::Reference);
61
60
      if (RHSVal == nullptr)
62
52
        return;
63
64
      // Assign a value to the storage location of the left-hand side.
65
8
      Env.setValue(*LHSLoc, *RHSVal);
66
67
      // Assign a storage location for the whole expression.
68
8
      Env.setStorageLocation(*S, *LHSLoc);
69
8
    }
70
    // FIXME: Add support for BO_EQ, BO_NE.
71
68
  }
72
73
178
  void VisitDeclRefExpr(const DeclRefExpr *S) {
74
178
    assert(S->getDecl() != nullptr);
75
0
    auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None);
76
178
    if (DeclLoc == nullptr)
77
28
      return;
78
79
150
    if (S->getDecl()->getType()->isReferenceType()) {
80
8
      Env.setStorageLocation(*S, *DeclLoc);
81
142
    } else {
82
142
      auto &Loc = Env.createStorageLocation(*S);
83
142
      auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc));
84
142
      Env.setStorageLocation(*S, Loc);
85
142
      Env.setValue(Loc, Val);
86
142
    }
87
150
  }
88
89
170
  void VisitDeclStmt(const DeclStmt *S) {
90
    // Group decls are converted into single decls in the CFG so the cast below
91
    // is safe.
92
170
    const auto &D = *cast<VarDecl>(S->getSingleDecl());
93
170
    auto &Loc = Env.createStorageLocation(D);
94
170
    Env.setStorageLocation(D, Loc);
95
96
170
    const Expr *InitExpr = D.getInit();
97
170
    if (InitExpr == nullptr) {
98
      // No initializer expression - associate `Loc` with a new value.
99
64
      if (Value *Val = Env.createValue(D.getType()))
100
64
        Env.setValue(Loc, *Val);
101
64
      return;
102
64
    }
103
104
    // The CFG does not contain `ParenExpr` as top-level statements in basic
105
    // blocks, however sub-expressions can still be of that type.
106
106
    InitExpr = skipExprWithCleanups(D.getInit()->IgnoreParens());
107
106
    assert(InitExpr != nullptr);
108
109
106
    if (D.getType()->isReferenceType()) {
110
      // Initializing a reference variable - do not create a reference to
111
      // reference.
112
10
      if (auto *InitExprLoc =
113
10
              Env.getStorageLocation(*InitExpr, SkipPast::Reference)) {
114
6
        auto &Val =
115
6
            Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
116
6
        Env.setValue(Loc, Val);
117
6
      } else {
118
        // FIXME: The initializer expression must always be assigned a value.
119
        // Replace this with an assert when we have sufficient coverage of
120
        // language features.
121
4
        if (Value *Val = Env.createValue(D.getType()))
122
4
          Env.setValue(Loc, *Val);
123
4
      }
124
10
      return;
125
10
    }
126
127
96
    if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
128
54
      Env.setValue(Loc, *InitExprVal);
129
54
    } else 
if (42
!D.getType()->isStructureOrClassType()42
) {
130
      // FIXME: The initializer expression must always be assigned a value.
131
      // Replace this with an assert when we have sufficient coverage of
132
      // language features.
133
42
      if (Value *Val = Env.createValue(D.getType()))
134
42
        Env.setValue(Loc, *Val);
135
42
    } else {
136
0
      llvm_unreachable("structs and classes must always be assigned values");
137
0
    }
138
96
  }
139
140
124
  void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
141
    // The CFG does not contain `ParenExpr` as top-level statements in basic
142
    // blocks, however sub-expressions can still be of that type.
143
124
    assert(S->getSubExpr() != nullptr);
144
0
    const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
145
124
    assert(SubExpr != nullptr);
146
147
0
    switch (S->getCastKind()) {
148
88
    case CK_LValueToRValue: {
149
88
      auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference);
150
88
      if (SubExprVal == nullptr)
151
0
        break;
152
153
88
      auto &ExprLoc = Env.createStorageLocation(*S);
154
88
      Env.setStorageLocation(*S, ExprLoc);
155
88
      Env.setValue(ExprLoc, *SubExprVal);
156
88
      break;
157
88
    }
158
8
    case CK_NoOp: {
159
      // FIXME: Consider making `Environment::getStorageLocation` skip noop
160
      // expressions (this and other similar expressions in the file) instead of
161
      // assigning them storage locations.
162
8
      auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
163
8
      if (SubExprLoc == nullptr)
164
0
        break;
165
166
8
      Env.setStorageLocation(*S, *SubExprLoc);
167
8
      break;
168
8
    }
169
28
    default:
170
      // FIXME: Add support for CK_UserDefinedConversion,
171
      // CK_ConstructorConversion, CK_UncheckedDerivedToBase.
172
28
      break;
173
124
    }
174
124
  }
175
176
4
  void VisitUnaryOperator(const UnaryOperator *S) {
177
4
    if (S->getOpcode() == UO_Deref) {
178
4
      assert(S->getSubExpr() != nullptr);
179
0
      const auto *SubExprVal = cast_or_null<PointerValue>(
180
4
          Env.getValue(*S->getSubExpr(), SkipPast::Reference));
181
4
      if (SubExprVal == nullptr)
182
0
        return;
183
184
4
      auto &Loc = Env.createStorageLocation(*S);
185
4
      Env.setStorageLocation(*S, Loc);
186
4
      Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
187
4
                            SubExprVal->getPointeeLoc())));
188
4
    }
189
    // FIXME: Add support for UO_AddrOf, UO_LNot.
190
4
  }
191
192
18
  void VisitCXXThisExpr(const CXXThisExpr *S) {
193
18
    auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
194
18
    assert(ThisPointeeLoc != nullptr);
195
196
0
    auto &Loc = Env.createStorageLocation(*S);
197
18
    Env.setStorageLocation(*S, Loc);
198
18
    Env.setValue(Loc, Env.takeOwnership(
199
18
                          std::make_unique<PointerValue>(*ThisPointeeLoc)));
200
18
  }
201
202
44
  void VisitMemberExpr(const MemberExpr *S) {
203
44
    ValueDecl *Member = S->getMemberDecl();
204
44
    assert(Member != nullptr);
205
206
    // FIXME: Consider assigning pointer values to function member expressions.
207
44
    if (Member->isFunctionOrFunctionTemplate())
208
14
      return;
209
210
    // The receiver can be either a value or a pointer to a value. Skip past the
211
    // indirection to handle both cases.
212
30
    auto *BaseLoc = cast_or_null<AggregateStorageLocation>(
213
30
        Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer));
214
30
    if (BaseLoc == nullptr)
215
0
      return;
216
217
    // FIXME: Add support for union types.
218
30
    if (BaseLoc->getType()->isUnionType())
219
0
      return;
220
221
30
    auto &MemberLoc = BaseLoc->getChild(*Member);
222
30
    if (MemberLoc.getType()->isReferenceType()) {
223
6
      Env.setStorageLocation(*S, MemberLoc);
224
24
    } else {
225
24
      auto &Loc = Env.createStorageLocation(*S);
226
24
      Env.setStorageLocation(*S, Loc);
227
24
      Env.setValue(
228
24
          Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc)));
229
24
    }
230
30
  }
231
232
4
  void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
233
4
    const Expr *InitExpr = S->getExpr();
234
4
    assert(InitExpr != nullptr);
235
236
0
    Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None);
237
4
    if (InitExprVal == nullptr)
238
0
      return;
239
240
4
    const FieldDecl *Field = S->getField();
241
4
    assert(Field != nullptr);
242
243
0
    auto &ThisLoc =
244
4
        *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
245
4
    auto &FieldLoc = ThisLoc.getChild(*Field);
246
4
    Env.setValue(FieldLoc, *InitExprVal);
247
4
  }
248
249
24
  void VisitCXXConstructExpr(const CXXConstructExpr *S) {
250
24
    const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
251
24
    assert(ConstructorDecl != nullptr);
252
253
24
    if (ConstructorDecl->isCopyOrMoveConstructor()) {
254
8
      assert(S->getNumArgs() == 1);
255
256
0
      const Expr *Arg = S->getArg(0);
257
8
      assert(Arg != nullptr);
258
259
8
      if (S->isElidable()) {
260
2
        auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
261
2
        if (ArgLoc == nullptr)
262
0
          return;
263
264
2
        Env.setStorageLocation(*S, *ArgLoc);
265
6
      } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) {
266
6
        auto &Loc = Env.createStorageLocation(*S);
267
6
        Env.setStorageLocation(*S, Loc);
268
6
        Env.setValue(Loc, *ArgVal);
269
6
      }
270
8
      return;
271
8
    }
272
273
16
    auto &Loc = Env.createStorageLocation(*S);
274
16
    Env.setStorageLocation(*S, Loc);
275
16
    if (Value *Val = Env.createValue(S->getType()))
276
16
      Env.setValue(Loc, *Val);
277
16
  }
278
279
4
  void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
280
4
    if (S->getOperator() == OO_Equal) {
281
4
      assert(S->getNumArgs() == 2);
282
283
0
      const Expr *Arg0 = S->getArg(0);
284
4
      assert(Arg0 != nullptr);
285
286
0
      const Expr *Arg1 = S->getArg(1);
287
4
      assert(Arg1 != nullptr);
288
289
      // Evaluate only copy and move assignment operators.
290
0
      auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType();
291
4
      auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType();
292
4
      if (Arg0Type != Arg1Type)
293
0
        return;
294
295
4
      auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference);
296
4
      if (ObjectLoc == nullptr)
297
0
        return;
298
299
4
      auto *Val = Env.getValue(*Arg1, SkipPast::Reference);
300
4
      if (Val == nullptr)
301
0
        return;
302
303
4
      Env.setValue(*ObjectLoc, *Val);
304
4
    }
305
4
  }
306
307
4
  void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
308
4
    if (S->getCastKind() == CK_ConstructorConversion) {
309
      // The CFG does not contain `ParenExpr` as top-level statements in basic
310
      // blocks, however sub-expressions can still be of that type.
311
4
      assert(S->getSubExpr() != nullptr);
312
0
      const Expr *SubExpr = S->getSubExpr();
313
4
      assert(SubExpr != nullptr);
314
315
0
      auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
316
4
      if (SubExprLoc == nullptr)
317
0
        return;
318
319
4
      Env.setStorageLocation(*S, *SubExprLoc);
320
4
    }
321
4
  }
322
323
18
  void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
324
18
    auto &Loc = Env.createStorageLocation(*S);
325
18
    Env.setStorageLocation(*S, Loc);
326
18
    if (Value *Val = Env.createValue(S->getType()))
327
18
      Env.setValue(Loc, *Val);
328
18
  }
329
330
38
  void VisitCallExpr(const CallExpr *S) {
331
38
    if (S->isCallToStdMove()) {
332
2
      assert(S->getNumArgs() == 1);
333
334
0
      const Expr *Arg = S->getArg(0);
335
2
      assert(Arg != nullptr);
336
337
0
      auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
338
2
      if (ArgLoc == nullptr)
339
0
        return;
340
341
2
      Env.setStorageLocation(*S, *ArgLoc);
342
2
    }
343
38
  }
344
345
18
  void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
346
18
    const Expr *SubExpr = S->getSubExpr();
347
18
    assert(SubExpr != nullptr);
348
349
0
    auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
350
18
    if (SubExprLoc == nullptr)
351
0
      return;
352
353
18
    Env.setStorageLocation(*S, *SubExprLoc);
354
18
  }
355
356
16
  void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
357
16
    const Expr *SubExpr = S->getSubExpr();
358
16
    assert(SubExpr != nullptr);
359
360
0
    auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
361
16
    if (SubExprLoc == nullptr)
362
0
      return;
363
364
16
    Env.setStorageLocation(*S, *SubExprLoc);
365
16
  }
366
367
2
  void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
368
2
    if (S->getCastKind() == CK_NoOp) {
369
2
      const Expr *SubExpr = S->getSubExpr();
370
2
      assert(SubExpr != nullptr);
371
372
0
      auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
373
2
      if (SubExprLoc == nullptr)
374
0
        return;
375
376
2
      Env.setStorageLocation(*S, *SubExprLoc);
377
2
    }
378
2
  }
379
380
  // FIXME: Add support for:
381
  // - CXXBoolLiteralExpr
382
383
private:
384
  Environment &Env;
385
};
386
387
22.7k
void transfer(const Stmt &S, Environment &Env) {
388
22.7k
  assert(!isa<ParenExpr>(&S));
389
0
  TransferVisitor(Env).Visit(&S);
390
22.7k
}
391
392
} // namespace dataflow
393
} // namespace clang