Coverage Report

Created: 2022-01-25 06:29

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- CastValueChecker - Model implementation of custom RTTIs --*- 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 defines CastValueChecker which models casts of custom RTTIs.
10
//
11
// TODO list:
12
// - It only allows one succesful cast between two types however in the wild
13
//   the object could be casted to multiple types.
14
// - It needs to check the most likely type information from the dynamic type
15
//   map to increase precision of dynamic casting.
16
//
17
//===----------------------------------------------------------------------===//
18
19
#include "clang/AST/DeclTemplate.h"
20
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
21
#include "clang/StaticAnalyzer/Core/Checker.h"
22
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
23
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
24
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
25
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
26
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
27
#include "llvm/ADT/Optional.h"
28
#include <utility>
29
30
using namespace clang;
31
using namespace ento;
32
33
namespace {
34
class CastValueChecker : public Checker<check::DeadSymbols, eval::Call> {
35
  enum class CallKind { Function, Method, InstanceOf };
36
37
  using CastCheck =
38
      std::function<void(const CastValueChecker *, const CallEvent &Call,
39
                         DefinedOrUnknownSVal, CheckerContext &)>;
40
41
public:
42
  // We have five cases to evaluate a cast:
43
  // 1) The parameter is non-null, the return value is non-null.
44
  // 2) The parameter is non-null, the return value is null.
45
  // 3) The parameter is null, the return value is null.
46
  // cast: 1;  dyn_cast: 1, 2;  cast_or_null: 1, 3;  dyn_cast_or_null: 1, 2, 3.
47
  //
48
  // 4) castAs: Has no parameter, the return value is non-null.
49
  // 5) getAs:  Has no parameter, the return value is null or non-null.
50
  //
51
  // We have two cases to check the parameter is an instance of the given type.
52
  // 1) isa:             The parameter is non-null, returns boolean.
53
  // 2) isa_and_nonnull: The parameter is null or non-null, returns boolean.
54
  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
55
  void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
56
57
private:
58
  // These are known in the LLVM project. The pairs are in the following form:
59
  // {{{namespace, call}, argument-count}, {callback, kind}}
60
  const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = {
61
      {{{"llvm", "cast"}, 1},
62
       {&CastValueChecker::evalCast, CallKind::Function}},
63
      {{{"llvm", "dyn_cast"}, 1},
64
       {&CastValueChecker::evalDynCast, CallKind::Function}},
65
      {{{"llvm", "cast_or_null"}, 1},
66
       {&CastValueChecker::evalCastOrNull, CallKind::Function}},
67
      {{{"llvm", "dyn_cast_or_null"}, 1},
68
       {&CastValueChecker::evalDynCastOrNull, CallKind::Function}},
69
      {{{"clang", "castAs"}, 0},
70
       {&CastValueChecker::evalCastAs, CallKind::Method}},
71
      {{{"clang", "getAs"}, 0},
72
       {&CastValueChecker::evalGetAs, CallKind::Method}},
73
      {{{"llvm", "isa"}, 1},
74
       {&CastValueChecker::evalIsa, CallKind::InstanceOf}},
75
      {{{"llvm", "isa_and_nonnull"}, 1},
76
       {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};
77
78
  void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
79
                CheckerContext &C) const;
80
  void evalDynCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
81
                   CheckerContext &C) const;
82
  void evalCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
83
                      CheckerContext &C) const;
84
  void evalDynCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
85
                         CheckerContext &C) const;
86
  void evalCastAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
87
                  CheckerContext &C) const;
88
  void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
89
                 CheckerContext &C) const;
90
  void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
91
               CheckerContext &C) const;
92
  void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
93
                         CheckerContext &C) const;
94
};
95
} // namespace
96
97
static bool isInfeasibleCast(const DynamicCastInfo *CastInfo,
98
58
                             bool CastSucceeds) {
99
58
  if (!CastInfo)
100
54
    return false;
101
102
4
  return CastSucceeds ? 
CastInfo->fails()2
:
CastInfo->succeeds()2
;
103
58
}
104
105
static const NoteTag *getNoteTag(CheckerContext &C,
106
                                 const DynamicCastInfo *CastInfo,
107
                                 QualType CastToTy, const Expr *Object,
108
75
                                 bool CastSucceeds, bool IsKnownCast) {
109
75
  std::string CastToName =
110
75
      CastInfo ? 
CastInfo->to()->getAsCXXRecordDecl()->getNameAsString()4
111
75
               : 
CastToTy->getPointeeCXXRecordDecl()->getNameAsString()71
;
112
75
  Object = Object->IgnoreParenImpCasts();
113
114
75
  return C.getNoteTag(
115
75
      [=]() -> std::string {
116
39
        SmallString<128> Msg;
117
39
        llvm::raw_svector_ostream Out(Msg);
118
119
39
        if (!IsKnownCast)
120
30
          Out << "Assuming ";
121
122
39
        if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
123
39
          Out << '\'' << DRE->getDecl()->getDeclName() << '\'';
124
39
        } else 
if (const auto *0
ME0
= dyn_cast<MemberExpr>(Object)) {
125
0
          Out << (IsKnownCast ? "Field '" : "field '")
126
0
              << ME->getMemberDecl()->getDeclName() << '\'';
127
0
        } else {
128
0
          Out << (IsKnownCast ? "The object" : "the object");
129
0
        }
130
131
39
        Out << ' ' << (CastSucceeds ? 
"is a"23
:
"is not a"16
) << " '" << CastToName
132
39
            << '\'';
133
134
39
        return std::string(Out.str());
135
39
      },
136
75
      /*IsPrunable=*/true);
137
75
}
138
139
static const NoteTag *getNoteTag(CheckerContext &C,
140
                                 SmallVector<QualType, 4> CastToTyVec,
141
                                 const Expr *Object,
142
21
                                 bool IsKnownCast) {
143
21
  Object = Object->IgnoreParenImpCasts();
144
145
21
  return C.getNoteTag(
146
21
      [=]() -> std::string {
147
10
        SmallString<128> Msg;
148
10
        llvm::raw_svector_ostream Out(Msg);
149
150
10
        if (!IsKnownCast)
151
4
          Out << "Assuming ";
152
153
10
        if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
154
10
          Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
155
10
        } else 
if (const auto *0
ME0
= dyn_cast<MemberExpr>(Object)) {
156
0
          Out << (IsKnownCast ? "Field '" : "field '")
157
0
              << ME->getMemberDecl()->getNameAsString() << '\'';
158
0
        } else {
159
0
          Out << (IsKnownCast ? "The object" : "the object");
160
0
        }
161
10
        Out << " is";
162
163
10
        bool First = true;
164
20
        for (QualType CastToTy: CastToTyVec) {
165
20
          std::string CastToName =
166
20
            CastToTy->getAsCXXRecordDecl() ?
167
20
            CastToTy->getAsCXXRecordDecl()->getNameAsString() :
168
20
            
CastToTy->getPointeeCXXRecordDecl()->getNameAsString()0
;
169
20
          Out << ' ' << ((CastToTyVec.size() == 1) ? 
"not"4
:
170
20
                         
(16
First16
?
"neither"6
:
"nor"10
)) << " a '" << CastToName
171
20
              << '\'';
172
20
          First = false;
173
20
        }
174
175
10
        return std::string(Out.str());
176
10
      },
177
21
      /*IsPrunable=*/true);
178
21
}
179
180
//===----------------------------------------------------------------------===//
181
// Main logic to evaluate a cast.
182
//===----------------------------------------------------------------------===//
183
184
static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards,
185
62
                                    ASTContext &ACtx) {
186
62
  if (alignTowards->isLValueReferenceType() &&
187
62
      alignTowards.isConstQualified()) {
188
0
    toAlign.addConst();
189
0
    return ACtx.getLValueReferenceType(toAlign);
190
62
  } else if (alignTowards->isLValueReferenceType())
191
62
    return ACtx.getLValueReferenceType(toAlign);
192
0
  else if (alignTowards->isRValueReferenceType())
193
0
    return ACtx.getRValueReferenceType(toAlign);
194
195
0
  llvm_unreachable("Must align towards a reference type!");
196
0
}
197
198
static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV,
199
                              CheckerContext &C, bool IsNonNullParam,
200
                              bool IsNonNullReturn,
201
63
                              bool IsCheckedCast = false) {
202
63
  ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam);
203
63
  if (!State)
204
4
    return;
205
206
59
  const Expr *Object;
207
59
  QualType CastFromTy;
208
59
  QualType CastToTy = Call.getResultType();
209
210
59
  if (Call.getNumArgs() > 0) {
211
52
    Object = Call.getArgExpr(0);
212
52
    CastFromTy = Call.parameters()[0]->getType();
213
52
  } else {
214
7
    Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
215
7
    CastFromTy = Object->getType();
216
7
    if (CastToTy->isPointerType()) {
217
7
      if (!CastFromTy->isPointerType())
218
1
        return;
219
7
    } else {
220
0
      if (!CastFromTy->isReferenceType())
221
0
        return;
222
223
0
      CastFromTy = alignReferenceTypes(CastFromTy, CastToTy, C.getASTContext());
224
0
    }
225
7
  }
226
227
58
  const MemRegion *MR = DV.getAsRegion();
228
58
  const DynamicCastInfo *CastInfo =
229
58
      getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
230
231
  // We assume that every checked cast succeeds.
232
58
  bool CastSucceeds = IsCheckedCast || 
CastFromTy == CastToTy53
;
233
58
  if (!CastSucceeds) {
234
53
    if (CastInfo)
235
4
      CastSucceeds = IsNonNullReturn && 
CastInfo->succeeds()2
;
236
49
    else
237
49
      CastSucceeds = IsNonNullReturn;
238
53
  }
239
240
  // Check for infeasible casts.
241
58
  if (isInfeasibleCast(CastInfo, CastSucceeds)) {
242
2
    C.generateSink(State, C.getPredecessor());
243
2
    return;
244
2
  }
245
246
  // Store the type and the cast information.
247
56
  bool IsKnownCast = CastInfo || 
IsCheckedCast54
||
CastFromTy == CastToTy49
;
248
56
  if (!IsKnownCast || 
IsCheckedCast7
)
249
54
    State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
250
54
                                      CastSucceeds);
251
252
56
  SVal V = CastSucceeds ? 
C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)32
253
56
                        : 
C.getSValBuilder().makeNull()24
;
254
56
  C.addTransition(
255
56
      State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
256
56
      getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
257
56
}
258
259
static void addInstanceOfTransition(const CallEvent &Call,
260
                                    DefinedOrUnknownSVal DV,
261
                                    ProgramStateRef State, CheckerContext &C,
262
34
                                    bool IsInstanceOf) {
263
34
  const FunctionDecl *FD = Call.getDecl()->getAsFunction();
264
34
  QualType CastFromTy = Call.parameters()[0]->getType();
265
34
  SmallVector<QualType, 4> CastToTyVec;
266
100
  for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1;
267
66
       ++idx) {
268
66
    TemplateArgument CastToTempArg =
269
66
      FD->getTemplateSpecializationArgs()->get(idx);
270
66
    switch (CastToTempArg.getKind()) {
271
0
    default:
272
0
      return;
273
42
    case TemplateArgument::Type:
274
42
      CastToTyVec.push_back(CastToTempArg.getAsType());
275
42
      break;
276
24
    case TemplateArgument::Pack:
277
24
      for (TemplateArgument ArgInPack: CastToTempArg.pack_elements())
278
28
        CastToTyVec.push_back(ArgInPack.getAsType());
279
24
      break;
280
66
    }
281
66
  }
282
283
34
  const MemRegion *MR = DV.getAsRegion();
284
34
  if (MR && CastFromTy->isReferenceType())
285
34
    MR = State->getSVal(DV.castAs<Loc>()).getAsRegion();
286
287
34
  bool Success = false;
288
34
  bool IsAnyKnown = false;
289
62
  for (QualType CastToTy: CastToTyVec) {
290
62
    if (CastFromTy->isPointerType())
291
0
      CastToTy = C.getASTContext().getPointerType(CastToTy);
292
62
    else if (CastFromTy->isReferenceType())
293
62
      CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext());
294
0
    else
295
0
      return;
296
297
62
    const DynamicCastInfo *CastInfo =
298
62
      getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
299
300
62
    bool CastSucceeds;
301
62
    if (CastInfo)
302
28
      CastSucceeds = IsInstanceOf && 
CastInfo->succeeds()14
;
303
34
    else
304
34
      CastSucceeds = IsInstanceOf || 
CastFromTy == CastToTy17
;
305
306
    // Store the type and the cast information.
307
62
    bool IsKnownCast = CastInfo || 
CastFromTy == CastToTy34
;
308
62
    IsAnyKnown = IsAnyKnown || 
IsKnownCast50
;
309
62
    ProgramStateRef NewState = State;
310
62
    if (!IsKnownCast)
311
34
      NewState = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
312
34
                                           IsInstanceOf);
313
314
62
    if (CastSucceeds) {
315
19
      Success = true;
316
19
      C.addTransition(
317
19
          NewState->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
318
19
                             C.getSValBuilder().makeTruthVal(true)),
319
19
          getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), true,
320
19
                     IsKnownCast));
321
19
      if (IsKnownCast)
322
2
        return;
323
43
    } else if (CastInfo && 
CastInfo->succeeds()26
) {
324
2
      C.generateSink(NewState, C.getPredecessor());
325
2
      return;
326
2
    }
327
62
  }
328
329
30
  if (!Success) {
330
21
    C.addTransition(
331
21
        State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
332
21
                        C.getSValBuilder().makeTruthVal(false)),
333
21
        getNoteTag(C, CastToTyVec, Call.getArgExpr(0), IsAnyKnown));
334
21
  }
335
30
}
336
337
//===----------------------------------------------------------------------===//
338
// Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null.
339
//===----------------------------------------------------------------------===//
340
341
static void evalNonNullParamNonNullReturn(const CallEvent &Call,
342
                                          DefinedOrUnknownSVal DV,
343
                                          CheckerContext &C,
344
30
                                          bool IsCheckedCast = false) {
345
30
  addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
346
30
                    /*IsNonNullReturn=*/true, IsCheckedCast);
347
30
}
348
349
static void evalNonNullParamNullReturn(const CallEvent &Call,
350
                                       DefinedOrUnknownSVal DV,
351
26
                                       CheckerContext &C) {
352
26
  addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
353
26
                    /*IsNonNullReturn=*/false);
354
26
}
355
356
static void evalNullParamNullReturn(const CallEvent &Call,
357
                                    DefinedOrUnknownSVal DV,
358
23
                                    CheckerContext &C) {
359
23
  if (ProgramStateRef State = C.getState()->assume(DV, false))
360
8
    C.addTransition(State->BindExpr(Call.getOriginExpr(),
361
8
                                    C.getLocationContext(),
362
8
                                    C.getSValBuilder().makeNull(), false),
363
8
                    C.getNoteTag("Assuming null pointer is passed into cast",
364
8
                                 /*IsPrunable=*/true));
365
23
}
366
367
void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
368
3
                                CheckerContext &C) const {
369
3
  evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
370
3
}
371
372
void CastValueChecker::evalDynCast(const CallEvent &Call,
373
                                   DefinedOrUnknownSVal DV,
374
4
                                   CheckerContext &C) const {
375
4
  evalNonNullParamNonNullReturn(Call, DV, C);
376
4
  evalNonNullParamNullReturn(Call, DV, C);
377
4
}
378
379
void CastValueChecker::evalCastOrNull(const CallEvent &Call,
380
                                      DefinedOrUnknownSVal DV,
381
1
                                      CheckerContext &C) const {
382
1
  evalNonNullParamNonNullReturn(Call, DV, C);
383
1
  evalNullParamNullReturn(Call, DV, C);
384
1
}
385
386
void CastValueChecker::evalDynCastOrNull(const CallEvent &Call,
387
                                         DefinedOrUnknownSVal DV,
388
22
                                         CheckerContext &C) const {
389
22
  evalNonNullParamNonNullReturn(Call, DV, C);
390
22
  evalNonNullParamNullReturn(Call, DV, C);
391
22
  evalNullParamNullReturn(Call, DV, C);
392
22
}
393
394
//===----------------------------------------------------------------------===//
395
// Evaluating castAs, getAs.
396
//===----------------------------------------------------------------------===//
397
398
static void evalZeroParamNonNullReturn(const CallEvent &Call,
399
                                       DefinedOrUnknownSVal DV,
400
                                       CheckerContext &C,
401
5
                                       bool IsCheckedCast = false) {
402
5
  addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
403
5
                    /*IsNonNullReturn=*/true, IsCheckedCast);
404
5
}
405
406
static void evalZeroParamNullReturn(const CallEvent &Call,
407
                                    DefinedOrUnknownSVal DV,
408
2
                                    CheckerContext &C) {
409
2
  addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
410
2
                    /*IsNonNullReturn=*/false);
411
2
}
412
413
void CastValueChecker::evalCastAs(const CallEvent &Call,
414
                                  DefinedOrUnknownSVal DV,
415
3
                                  CheckerContext &C) const {
416
3
  evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
417
3
}
418
419
void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
420
2
                                 CheckerContext &C) const {
421
2
  evalZeroParamNonNullReturn(Call, DV, C);
422
2
  evalZeroParamNullReturn(Call, DV, C);
423
2
}
424
425
//===----------------------------------------------------------------------===//
426
// Evaluating isa, isa_and_nonnull.
427
//===----------------------------------------------------------------------===//
428
429
void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
430
13
                               CheckerContext &C) const {
431
13
  ProgramStateRef NonNullState, NullState;
432
13
  std::tie(NonNullState, NullState) = C.getState()->assume(DV);
433
434
13
  if (NonNullState) {
435
13
    addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
436
13
    addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
437
13
  }
438
439
13
  if (NullState) {
440
0
    C.generateSink(NullState, C.getPredecessor());
441
0
  }
442
13
}
443
444
void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call,
445
                                         DefinedOrUnknownSVal DV,
446
4
                                         CheckerContext &C) const {
447
4
  ProgramStateRef NonNullState, NullState;
448
4
  std::tie(NonNullState, NullState) = C.getState()->assume(DV);
449
450
4
  if (NonNullState) {
451
4
    addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
452
4
    addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
453
4
  }
454
455
4
  if (NullState) {
456
0
    addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false);
457
0
  }
458
4
}
459
460
//===----------------------------------------------------------------------===//
461
// Main logic to evaluate a call.
462
//===----------------------------------------------------------------------===//
463
464
bool CastValueChecker::evalCall(const CallEvent &Call,
465
258
                                CheckerContext &C) const {
466
258
  const auto *Lookup = CDM.lookup(Call);
467
258
  if (!Lookup)
468
203
    return false;
469
470
55
  const CastCheck &Check = Lookup->first;
471
55
  CallKind Kind = Lookup->second;
472
473
55
  Optional<DefinedOrUnknownSVal> DV;
474
475
55
  switch (Kind) {
476
33
  case CallKind::Function: {
477
    // We only model casts from pointers to pointers or from references
478
    // to references. Other casts are most likely specialized and we
479
    // cannot model them.
480
33
    QualType ParamT = Call.parameters()[0]->getType();
481
33
    QualType ResultT = Call.getResultType();
482
33
    if (!(ParamT->isPointerType() && 
ResultT->isPointerType()29
) &&
483
33
        
!(4
ParamT->isReferenceType()4
&&
ResultT->isReferenceType()3
)) {
484
3
      return false;
485
3
    }
486
487
30
    DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
488
30
    break;
489
33
  }
490
17
  case CallKind::InstanceOf: {
491
    // We need to obtain the only template argument to determinte the type.
492
17
    const FunctionDecl *FD = Call.getDecl()->getAsFunction();
493
17
    if (!FD || !FD->getTemplateSpecializationArgs())
494
0
      return false;
495
496
17
    DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
497
17
    break;
498
17
  }
499
5
  case CallKind::Method:
500
5
    const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call);
501
5
    if (!InstanceCall)
502
0
      return false;
503
504
5
    DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>();
505
5
    break;
506
55
  }
507
508
52
  if (!DV)
509
0
    return false;
510
511
52
  Check(this, Call, *DV, C);
512
52
  return true;
513
52
}
514
515
void CastValueChecker::checkDeadSymbols(SymbolReaper &SR,
516
3.02k
                                        CheckerContext &C) const {
517
3.02k
  C.addTransition(removeDeadCasts(C.getState(), SR));
518
3.02k
}
519
520
43
void ento::registerCastValueChecker(CheckerManager &Mgr) {
521
43
  Mgr.registerChecker<CastValueChecker>();
522
43
}
523
524
90
bool ento::shouldRegisterCastValueChecker(const CheckerManager &mgr) {
525
90
  return true;
526
90
}