Coverage Report

Created: 2023-09-12 09:32

/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 <optional>
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
372
                             bool CastSucceeds) {
99
372
  if (!CastInfo)
100
336
    return false;
101
102
36
  return CastSucceeds ? 
CastInfo->fails()18
:
CastInfo->succeeds()18
;
103
372
}
104
105
static const NoteTag *getNoteTag(CheckerContext &C,
106
                                 const DynamicCastInfo *CastInfo,
107
                                 QualType CastToTy, const Expr *Object,
108
398
                                 bool CastSucceeds, bool IsKnownCast) {
109
398
  std::string CastToName =
110
398
      CastInfo ? 
CastInfo->to()->getAsCXXRecordDecl()->getNameAsString()36
111
398
               : 
CastToTy.getAsString()362
;
112
398
  Object = Object->IgnoreParenImpCasts();
113
114
398
  return C.getNoteTag(
115
398
      [=]() -> std::string {
116
184
        SmallString<128> Msg;
117
184
        llvm::raw_svector_ostream Out(Msg);
118
119
184
        if (!IsKnownCast)
120
135
          Out << "Assuming ";
121
122
184
        if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
123
184
          Out << '\'' << DRE->getDecl()->getDeclName() << '\'';
124
184
        } 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
184
        Out << ' ' << (CastSucceeds ? 
"is a"95
:
"is not a"89
) << " '" << CastToName
132
184
            << '\'';
133
134
184
        return std::string(Out.str());
135
184
      },
136
398
      /*IsPrunable=*/true);
137
398
}
138
139
static const NoteTag *getNoteTag(CheckerContext &C,
140
                                 SmallVector<QualType, 4> CastToTyVec,
141
                                 const Expr *Object,
142
126
                                 bool IsKnownCast) {
143
126
  Object = Object->IgnoreParenImpCasts();
144
145
126
  return C.getNoteTag(
146
126
      [=]() -> std::string {
147
58
        SmallString<128> Msg;
148
58
        llvm::raw_svector_ostream Out(Msg);
149
150
58
        if (!IsKnownCast)
151
4
          Out << "Assuming ";
152
153
58
        if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
154
58
          Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
155
58
        } 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
58
        Out << " is";
162
163
58
        bool First = true;
164
116
        for (QualType CastToTy: CastToTyVec) {
165
116
          std::string CastToName =
166
116
              CastToTy->getAsCXXRecordDecl()
167
116
                  ? CastToTy->getAsCXXRecordDecl()->getNameAsString()
168
116
                  : 
CastToTy.getAsString()0
;
169
116
          Out << ' ' << ((CastToTyVec.size() == 1) ? 
"not"20
:
170
116
                         
(96
First96
?
"neither"38
:
"nor"58
)) << " a '" << CastToName
171
116
              << '\'';
172
116
          First = false;
173
116
        }
174
175
58
        return std::string(Out.str());
176
58
      },
177
126
      /*IsPrunable=*/true);
178
126
}
179
180
//===----------------------------------------------------------------------===//
181
// Main logic to evaluate a cast.
182
//===----------------------------------------------------------------------===//
183
184
static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards,
185
304
                                    ASTContext &ACtx) {
186
304
  if (alignTowards->isLValueReferenceType() &&
187
304
      alignTowards.isConstQualified()) {
188
0
    toAlign.addConst();
189
0
    return ACtx.getLValueReferenceType(toAlign);
190
304
  } else if (alignTowards->isLValueReferenceType())
191
304
    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
401
                              bool IsCheckedCast = false) {
202
401
  ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam);
203
401
  if (!State)
204
20
    return;
205
206
381
  const Expr *Object;
207
381
  QualType CastFromTy;
208
381
  QualType CastToTy = Call.getResultType();
209
210
381
  if (Call.getNumArgs() > 0) {
211
342
    Object = Call.getArgExpr(0);
212
342
    CastFromTy = Call.parameters()[0]->getType();
213
342
  } else {
214
39
    Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
215
39
    CastFromTy = Object->getType();
216
39
    if (CastToTy->isPointerType()) {
217
39
      if (!CastFromTy->isPointerType())
218
9
        return;
219
39
    } else {
220
0
      if (!CastFromTy->isReferenceType())
221
0
        return;
222
223
0
      CastFromTy = alignReferenceTypes(CastFromTy, CastToTy, C.getASTContext());
224
0
    }
225
39
  }
226
227
372
  const MemRegion *MR = DV.getAsRegion();
228
372
  const DynamicCastInfo *CastInfo =
229
372
      getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
230
231
  // We assume that every checked cast succeeds.
232
372
  bool CastSucceeds = IsCheckedCast || 
CastFromTy == CastToTy351
;
233
372
  if (!CastSucceeds) {
234
351
    if (CastInfo)
235
36
      CastSucceeds = IsNonNullReturn && 
CastInfo->succeeds()18
;
236
315
    else
237
315
      CastSucceeds = IsNonNullReturn;
238
351
  }
239
240
  // Check for infeasible casts.
241
372
  if (isInfeasibleCast(CastInfo, CastSucceeds)) {
242
18
    C.generateSink(State, C.getPredecessor());
243
18
    return;
244
18
  }
245
246
  // Store the type and the cast information.
247
354
  bool IsKnownCast = CastInfo || 
IsCheckedCast336
||
CastFromTy == CastToTy315
;
248
354
  if (!IsKnownCast || 
IsCheckedCast39
)
249
336
    State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
250
336
                                      CastSucceeds);
251
252
354
  SVal V = CastSucceeds ? 
C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)197
253
354
                        : 
C.getSValBuilder().makeNullWithType(CastToTy)157
;
254
354
  C.addTransition(
255
354
      State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
256
354
      getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
257
354
}
258
259
static void addInstanceOfTransition(const CallEvent &Call,
260
                                    DefinedOrUnknownSVal DV,
261
                                    ProgramStateRef State, CheckerContext &C,
262
180
                                    bool IsInstanceOf) {
263
180
  const FunctionDecl *FD = Call.getDecl()->getAsFunction();
264
180
  QualType CastFromTy = Call.parameters()[0]->getType();
265
180
  SmallVector<QualType, 4> CastToTyVec;
266
584
  for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1;
267
404
       ++idx) {
268
404
    TemplateArgument CastToTempArg =
269
404
      FD->getTemplateSpecializationArgs()->get(idx);
270
404
    switch (CastToTempArg.getKind()) {
271
0
    default:
272
0
      return;
273
284
    case TemplateArgument::Type:
274
284
      CastToTyVec.push_back(CastToTempArg.getAsType());
275
284
      break;
276
120
    case TemplateArgument::Pack:
277
120
      for (TemplateArgument ArgInPack: CastToTempArg.pack_elements())
278
92
        CastToTyVec.push_back(ArgInPack.getAsType());
279
120
      break;
280
404
    }
281
404
  }
282
283
180
  const MemRegion *MR = DV.getAsRegion();
284
180
  if (MR && CastFromTy->isReferenceType())
285
180
    MR = State->getSVal(DV.castAs<Loc>()).getAsRegion();
286
287
180
  bool Success = false;
288
180
  bool IsAnyKnown = false;
289
304
  for (QualType CastToTy: CastToTyVec) {
290
304
    if (CastFromTy->isPointerType())
291
0
      CastToTy = C.getASTContext().getPointerType(CastToTy);
292
304
    else if (CastFromTy->isReferenceType())
293
304
      CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext());
294
0
    else
295
0
      return;
296
297
304
    const DynamicCastInfo *CastInfo =
298
304
      getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
299
300
304
    bool CastSucceeds;
301
304
    if (CastInfo)
302
252
      CastSucceeds = IsInstanceOf && 
CastInfo->succeeds()126
;
303
52
    else
304
52
      CastSucceeds = IsInstanceOf || 
CastFromTy == CastToTy26
;
305
306
    // Store the type and the cast information.
307
304
    bool IsKnownCast = CastInfo || 
CastFromTy == CastToTy52
;
308
304
    IsAnyKnown = IsAnyKnown || 
IsKnownCast196
;
309
304
    ProgramStateRef NewState = State;
310
304
    if (!IsKnownCast)
311
52
      NewState = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
312
52
                                           IsInstanceOf);
313
314
304
    if (CastSucceeds) {
315
44
      Success = true;
316
44
      C.addTransition(
317
44
          NewState->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
318
44
                             C.getSValBuilder().makeTruthVal(true)),
319
44
          getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), true,
320
44
                     IsKnownCast));
321
44
      if (IsKnownCast)
322
18
        return;
323
260
    } else if (CastInfo && 
CastInfo->succeeds()234
) {
324
18
      C.generateSink(NewState, C.getPredecessor());
325
18
      return;
326
18
    }
327
304
  }
328
329
144
  if (!Success) {
330
126
    C.addTransition(
331
126
        State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
332
126
                        C.getSValBuilder().makeTruthVal(false)),
333
126
        getNoteTag(C, CastToTyVec, Call.getArgExpr(0), IsAnyKnown));
334
126
  }
335
144
}
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
187
                                          bool IsCheckedCast = false) {
345
187
  addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
346
187
                    /*IsNonNullReturn=*/true, IsCheckedCast);
347
187
}
348
349
static void evalNonNullParamNullReturn(const CallEvent &Call,
350
                                       DefinedOrUnknownSVal DV,
351
175
                                       CheckerContext &C) {
352
175
  addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
353
175
                    /*IsNonNullReturn=*/false);
354
175
}
355
356
static void evalNullParamNullReturn(const CallEvent &Call,
357
                                    DefinedOrUnknownSVal DV,
358
159
                                    CheckerContext &C) {
359
159
  if (ProgramStateRef State = C.getState()->assume(DV, false))
360
40
    C.addTransition(State->BindExpr(Call.getOriginExpr(),
361
40
                                    C.getLocationContext(),
362
40
                                    C.getSValBuilder().makeNullWithType(
363
40
                                        Call.getOriginExpr()->getType()),
364
40
                                    false),
365
40
                    C.getNoteTag("Assuming null pointer is passed into cast",
366
40
                                 /*IsPrunable=*/true));
367
159
}
368
369
void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
370
11
                                CheckerContext &C) const {
371
11
  evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
372
11
}
373
374
void CastValueChecker::evalDynCast(const CallEvent &Call,
375
                                   DefinedOrUnknownSVal DV,
376
17
                                   CheckerContext &C) const {
377
17
  evalNonNullParamNonNullReturn(Call, DV, C);
378
17
  evalNonNullParamNullReturn(Call, DV, C);
379
17
}
380
381
void CastValueChecker::evalCastOrNull(const CallEvent &Call,
382
                                      DefinedOrUnknownSVal DV,
383
1
                                      CheckerContext &C) const {
384
1
  evalNonNullParamNonNullReturn(Call, DV, C);
385
1
  evalNullParamNullReturn(Call, DV, C);
386
1
}
387
388
void CastValueChecker::evalDynCastOrNull(const CallEvent &Call,
389
                                         DefinedOrUnknownSVal DV,
390
158
                                         CheckerContext &C) const {
391
158
  evalNonNullParamNonNullReturn(Call, DV, C);
392
158
  evalNonNullParamNullReturn(Call, DV, C);
393
158
  evalNullParamNullReturn(Call, DV, C);
394
158
}
395
396
//===----------------------------------------------------------------------===//
397
// Evaluating castAs, getAs.
398
//===----------------------------------------------------------------------===//
399
400
static void evalZeroParamNonNullReturn(const CallEvent &Call,
401
                                       DefinedOrUnknownSVal DV,
402
                                       CheckerContext &C,
403
29
                                       bool IsCheckedCast = false) {
404
29
  addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
405
29
                    /*IsNonNullReturn=*/true, IsCheckedCast);
406
29
}
407
408
static void evalZeroParamNullReturn(const CallEvent &Call,
409
                                    DefinedOrUnknownSVal DV,
410
10
                                    CheckerContext &C) {
411
10
  addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
412
10
                    /*IsNonNullReturn=*/false);
413
10
}
414
415
void CastValueChecker::evalCastAs(const CallEvent &Call,
416
                                  DefinedOrUnknownSVal DV,
417
19
                                  CheckerContext &C) const {
418
19
  evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
419
19
}
420
421
void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
422
10
                                 CheckerContext &C) const {
423
10
  evalZeroParamNonNullReturn(Call, DV, C);
424
10
  evalZeroParamNullReturn(Call, DV, C);
425
10
}
426
427
//===----------------------------------------------------------------------===//
428
// Evaluating isa, isa_and_nonnull.
429
//===----------------------------------------------------------------------===//
430
431
void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
432
86
                               CheckerContext &C) const {
433
86
  ProgramStateRef NonNullState, NullState;
434
86
  std::tie(NonNullState, NullState) = C.getState()->assume(DV);
435
436
86
  if (NonNullState) {
437
86
    addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
438
86
    addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
439
86
  }
440
441
86
  if (NullState) {
442
0
    C.generateSink(NullState, C.getPredecessor());
443
0
  }
444
86
}
445
446
void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call,
447
                                         DefinedOrUnknownSVal DV,
448
4
                                         CheckerContext &C) const {
449
4
  ProgramStateRef NonNullState, NullState;
450
4
  std::tie(NonNullState, NullState) = C.getState()->assume(DV);
451
452
4
  if (NonNullState) {
453
4
    addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
454
4
    addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
455
4
  }
456
457
4
  if (NullState) {
458
0
    addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false);
459
0
  }
460
4
}
461
462
//===----------------------------------------------------------------------===//
463
// Main logic to evaluate a call.
464
//===----------------------------------------------------------------------===//
465
466
bool CastValueChecker::evalCall(const CallEvent &Call,
467
586
                                CheckerContext &C) const {
468
586
  const auto *Lookup = CDM.lookup(Call);
469
586
  if (!Lookup)
470
269
    return false;
471
472
317
  const CastCheck &Check = Lookup->first;
473
317
  CallKind Kind = Lookup->second;
474
475
317
  std::optional<DefinedOrUnknownSVal> DV;
476
477
317
  switch (Kind) {
478
198
  case CallKind::Function: {
479
    // We only model casts from pointers to pointers or from references
480
    // to references. Other casts are most likely specialized and we
481
    // cannot model them.
482
198
    QualType ParamT = Call.parameters()[0]->getType();
483
198
    QualType ResultT = Call.getResultType();
484
198
    if (!(ParamT->isPointerType() && 
ResultT->isPointerType()173
) &&
485
198
        
!(25
ParamT->isReferenceType()25
&&
ResultT->isReferenceType()24
)) {
486
11
      return false;
487
11
    }
488
489
187
    DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
490
187
    break;
491
198
  }
492
90
  case CallKind::InstanceOf: {
493
    // We need to obtain the only template argument to determinte the type.
494
90
    const FunctionDecl *FD = Call.getDecl()->getAsFunction();
495
90
    if (!FD || !FD->getTemplateSpecializationArgs())
496
0
      return false;
497
498
90
    DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
499
90
    break;
500
90
  }
501
29
  case CallKind::Method:
502
29
    const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call);
503
29
    if (!InstanceCall)
504
0
      return false;
505
506
29
    DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>();
507
29
    break;
508
317
  }
509
510
306
  if (!DV)
511
0
    return false;
512
513
306
  Check(this, Call, *DV, C);
514
306
  return true;
515
306
}
516
517
void CastValueChecker::checkDeadSymbols(SymbolReaper &SR,
518
4.26k
                                        CheckerContext &C) const {
519
4.26k
  C.addTransition(removeDeadCasts(C.getState(), SR));
520
4.26k
}
521
522
52
void ento::registerCastValueChecker(CheckerManager &Mgr) {
523
52
  Mgr.registerChecker<CastValueChecker>();
524
52
}
525
526
108
bool ento::shouldRegisterCastValueChecker(const CheckerManager &mgr) {
527
108
  return true;
528
108
}