blob: 5c4daa3e428be4a250e6214e7545ccdf7bbc3bf7 [file] [log] [blame]
Csaba Dabis693936a2019-07-10 00:20:03 +00001//===- 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//
Csaba Dabis0202c352019-08-22 00:20:36 +00009// 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.
Csaba Dabis693936a2019-07-10 00:20:03 +000016//
17//===----------------------------------------------------------------------===//
18
Csaba Dabis4d716002019-08-22 02:57:59 +000019#include "clang/AST/DeclTemplate.h"
Csaba Dabis693936a2019-07-10 00:20:03 +000020#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/CallEvent.h"
24#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Csaba Dabis0202c352019-08-22 00:20:36 +000025#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
Csaba Dabis693936a2019-07-10 00:20:03 +000026#include "llvm/ADT/Optional.h"
Csaba Dabiscf229d52019-08-09 02:24:42 +000027#include <utility>
Csaba Dabis693936a2019-07-10 00:20:03 +000028
29using namespace clang;
30using namespace ento;
31
32namespace {
33class CastValueChecker : public Checker<eval::Call> {
Csaba Dabis4d716002019-08-22 02:57:59 +000034 enum class CallKind { Function, Method, InstanceOf };
Csaba Dabiscf229d52019-08-09 02:24:42 +000035
Csaba Dabis693936a2019-07-10 00:20:03 +000036 using CastCheck =
Csaba Dabis0202c352019-08-22 00:20:36 +000037 std::function<void(const CastValueChecker *, const CallEvent &Call,
Csaba Dabis693936a2019-07-10 00:20:03 +000038 DefinedOrUnknownSVal, CheckerContext &)>;
39
40public:
Csaba Dabiscf229d52019-08-09 02:24:42 +000041 // We have five cases to evaluate a cast:
Csaba Dabis0202c352019-08-22 00:20:36 +000042 // 1) The parameter is non-null, the return value is non-null.
43 // 2) The parameter is non-null, the return value is null.
44 // 3) The parameter is null, the return value is null.
Csaba Dabis693936a2019-07-10 00:20:03 +000045 // cast: 1; dyn_cast: 1, 2; cast_or_null: 1, 3; dyn_cast_or_null: 1, 2, 3.
Csaba Dabiscf229d52019-08-09 02:24:42 +000046 //
Csaba Dabis0202c352019-08-22 00:20:36 +000047 // 4) castAs: Has no parameter, the return value is non-null.
48 // 5) getAs: Has no parameter, the return value is null or non-null.
Csaba Dabis4d716002019-08-22 02:57:59 +000049 //
50 // We have two cases to check the parameter is an instance of the given type.
51 // 1) isa: The parameter is non-null, returns boolean.
52 // 2) isa_and_nonnull: The parameter is null or non-null, returns boolean.
Csaba Dabis693936a2019-07-10 00:20:03 +000053 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000054 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
Csaba Dabis693936a2019-07-10 00:20:03 +000055
56private:
Csaba Dabiscf229d52019-08-09 02:24:42 +000057 // These are known in the LLVM project. The pairs are in the following form:
58 // {{{namespace, call}, argument-count}, {callback, kind}}
Csaba Dabis0202c352019-08-22 00:20:36 +000059 const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = {
Csaba Dabiscf229d52019-08-09 02:24:42 +000060 {{{"llvm", "cast"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000061 {&CastValueChecker::evalCast, CallKind::Function}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000062 {{{"llvm", "dyn_cast"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000063 {&CastValueChecker::evalDynCast, CallKind::Function}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000064 {{{"llvm", "cast_or_null"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000065 {&CastValueChecker::evalCastOrNull, CallKind::Function}},
Csaba Dabis693936a2019-07-10 00:20:03 +000066 {{{"llvm", "dyn_cast_or_null"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000067 {&CastValueChecker::evalDynCastOrNull, CallKind::Function}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000068 {{{"clang", "castAs"}, 0},
Csaba Dabis0202c352019-08-22 00:20:36 +000069 {&CastValueChecker::evalCastAs, CallKind::Method}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000070 {{{"clang", "getAs"}, 0},
Csaba Dabis4d716002019-08-22 02:57:59 +000071 {&CastValueChecker::evalGetAs, CallKind::Method}},
72 {{{"llvm", "isa"}, 1},
73 {&CastValueChecker::evalIsa, CallKind::InstanceOf}},
74 {{{"llvm", "isa_and_nonnull"}, 1},
75 {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};
Csaba Dabis693936a2019-07-10 00:20:03 +000076
Csaba Dabis0202c352019-08-22 00:20:36 +000077 void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000078 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000079 void evalDynCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000080 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000081 void evalCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000082 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000083 void evalDynCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000084 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000085 void evalCastAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +000086 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000087 void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +000088 CheckerContext &C) const;
Csaba Dabis4d716002019-08-22 02:57:59 +000089 void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
90 CheckerContext &C) const;
91 void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
92 CheckerContext &C) const;
Csaba Dabis693936a2019-07-10 00:20:03 +000093};
94} // namespace
95
Csaba Dabis0202c352019-08-22 00:20:36 +000096static QualType getRecordType(QualType Ty) {
97 Ty = Ty.getCanonicalType();
Csaba Dabiscf229d52019-08-09 02:24:42 +000098
Csaba Dabis0202c352019-08-22 00:20:36 +000099 if (Ty->isPointerType())
100 Ty = Ty->getPointeeType();
101
102 if (Ty->isReferenceType())
103 Ty = Ty.getNonReferenceType();
104
105 return Ty.getUnqualifiedType();
Csaba Dabis693936a2019-07-10 00:20:03 +0000106}
107
Csaba Dabis0202c352019-08-22 00:20:36 +0000108static bool isInfeasibleCast(const DynamicCastInfo *CastInfo,
109 bool CastSucceeds) {
110 if (!CastInfo)
111 return false;
112
113 return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds();
114}
115
116static const NoteTag *getNoteTag(CheckerContext &C,
117 const DynamicCastInfo *CastInfo,
118 QualType CastToTy, const Expr *Object,
119 bool CastSucceeds, bool IsKnownCast) {
120 std::string CastToName =
121 CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString()
122 : CastToTy->getAsCXXRecordDecl()->getNameAsString();
123 Object = Object->IgnoreParenImpCasts();
Csaba Dabis693936a2019-07-10 00:20:03 +0000124
Csaba Dabiscf229d52019-08-09 02:24:42 +0000125 return C.getNoteTag(
Csaba Dabis22dc44f2019-08-22 01:41:06 +0000126 [=]() -> std::string {
Csaba Dabis693936a2019-07-10 00:20:03 +0000127 SmallString<128> Msg;
128 llvm::raw_svector_ostream Out(Msg);
129
Csaba Dabis0202c352019-08-22 00:20:36 +0000130 if (!IsKnownCast)
131 Out << "Assuming ";
Csaba Dabiscf229d52019-08-09 02:24:42 +0000132
Csaba Dabis0202c352019-08-22 00:20:36 +0000133 if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
134 Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
135 } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) {
136 Out << (IsKnownCast ? "Field '" : "field '")
137 << ME->getMemberDecl()->getNameAsString() << '\'';
138 } else {
139 Out << (IsKnownCast ? "The object" : "the object");
140 }
141
142 Out << ' ' << (CastSucceeds ? "is a" : "is not a") << " '" << CastToName
143 << '\'';
Csaba Dabiscf229d52019-08-09 02:24:42 +0000144
Csaba Dabis693936a2019-07-10 00:20:03 +0000145 return Out.str();
146 },
147 /*IsPrunable=*/true);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000148}
Csaba Dabis693936a2019-07-10 00:20:03 +0000149
Csaba Dabis0202c352019-08-22 00:20:36 +0000150//===----------------------------------------------------------------------===//
151// Main logic to evaluate a cast.
152//===----------------------------------------------------------------------===//
153
154static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV,
155 CheckerContext &C, bool IsNonNullParam,
156 bool IsNonNullReturn,
157 bool IsCheckedCast = false) {
158 ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam);
159 if (!State)
160 return;
161
162 const Expr *Object;
163 QualType CastFromTy;
164 QualType CastToTy = getRecordType(Call.getResultType());
165
166 if (Call.getNumArgs() > 0) {
167 Object = Call.getArgExpr(0);
168 CastFromTy = getRecordType(Call.parameters()[0]->getType());
169 } else {
170 Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
171 CastFromTy = getRecordType(Object->getType());
172 }
173
174 const MemRegion *MR = DV.getAsRegion();
175 const DynamicCastInfo *CastInfo =
176 getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
177
178 // We assume that every checked cast succeeds.
179 bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
180 if (!CastSucceeds) {
181 if (CastInfo)
182 CastSucceeds = IsNonNullReturn && CastInfo->succeeds();
183 else
184 CastSucceeds = IsNonNullReturn;
185 }
186
187 // Check for infeasible casts.
188 if (isInfeasibleCast(CastInfo, CastSucceeds)) {
189 C.generateSink(State, C.getPredecessor());
190 return;
191 }
192
193 // Store the type and the cast information.
194 bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
195 if (!IsKnownCast || IsCheckedCast)
196 State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
197 Call.getResultType(), CastSucceeds);
198
199 SVal V = CastSucceeds ? DV : C.getSValBuilder().makeNull();
200 C.addTransition(
201 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
202 getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
Csaba Dabiscf229d52019-08-09 02:24:42 +0000203}
204
Csaba Dabis4d716002019-08-22 02:57:59 +0000205static void addInstanceOfTransition(const CallEvent &Call,
206 DefinedOrUnknownSVal DV,
207 ProgramStateRef State, CheckerContext &C,
208 bool IsInstanceOf) {
209 const FunctionDecl *FD = Call.getDecl()->getAsFunction();
210 QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType();
211 QualType CastFromTy = getRecordType(Call.parameters()[0]->getType());
212
213 const MemRegion *MR = DV.getAsRegion();
214 const DynamicCastInfo *CastInfo =
215 getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
216
217 bool CastSucceeds;
218 if (CastInfo)
219 CastSucceeds = IsInstanceOf && CastInfo->succeeds();
220 else
221 CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
222
223 if (isInfeasibleCast(CastInfo, CastSucceeds)) {
224 C.generateSink(State, C.getPredecessor());
225 return;
226 }
227
228 // Store the type and the cast information.
229 bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
230 if (!IsKnownCast)
231 State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
232 Call.getResultType(), IsInstanceOf);
233
234 C.addTransition(
235 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
236 C.getSValBuilder().makeTruthVal(CastSucceeds)),
237 getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds,
238 IsKnownCast));
239}
240
Csaba Dabiscf229d52019-08-09 02:24:42 +0000241//===----------------------------------------------------------------------===//
242// Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null.
243//===----------------------------------------------------------------------===//
244
Csaba Dabis0202c352019-08-22 00:20:36 +0000245static void evalNonNullParamNonNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000246 DefinedOrUnknownSVal DV,
247 CheckerContext &C,
248 bool IsCheckedCast = false) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000249 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
250 /*IsNonNullReturn=*/true, IsCheckedCast);
Csaba Dabis693936a2019-07-10 00:20:03 +0000251}
252
Csaba Dabis0202c352019-08-22 00:20:36 +0000253static void evalNonNullParamNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000254 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000255 CheckerContext &C) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000256 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
257 /*IsNonNullReturn=*/false);
Csaba Dabis693936a2019-07-10 00:20:03 +0000258}
259
Csaba Dabis0202c352019-08-22 00:20:36 +0000260static void evalNullParamNullReturn(const CallEvent &Call,
261 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000262 CheckerContext &C) {
Csaba Dabiscf229d52019-08-09 02:24:42 +0000263 if (ProgramStateRef State = C.getState()->assume(DV, false))
Csaba Dabis0202c352019-08-22 00:20:36 +0000264 C.addTransition(State->BindExpr(Call.getOriginExpr(),
265 C.getLocationContext(),
266 C.getSValBuilder().makeNull(), false),
Csaba Dabiscf229d52019-08-09 02:24:42 +0000267 C.getNoteTag("Assuming null pointer is passed into cast",
268 /*IsPrunable=*/true));
Csaba Dabis693936a2019-07-10 00:20:03 +0000269}
270
Csaba Dabis0202c352019-08-22 00:20:36 +0000271void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000272 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000273 evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
Csaba Dabis693936a2019-07-10 00:20:03 +0000274}
275
Csaba Dabis0202c352019-08-22 00:20:36 +0000276void CastValueChecker::evalDynCast(const CallEvent &Call,
277 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000278 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000279 evalNonNullParamNonNullReturn(Call, DV, C);
280 evalNonNullParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000281}
282
Csaba Dabis0202c352019-08-22 00:20:36 +0000283void CastValueChecker::evalCastOrNull(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000284 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000285 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000286 evalNonNullParamNonNullReturn(Call, DV, C);
287 evalNullParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000288}
289
Csaba Dabis0202c352019-08-22 00:20:36 +0000290void CastValueChecker::evalDynCastOrNull(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000291 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000292 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000293 evalNonNullParamNonNullReturn(Call, DV, C);
294 evalNonNullParamNullReturn(Call, DV, C);
295 evalNullParamNullReturn(Call, DV, C);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000296}
297
298//===----------------------------------------------------------------------===//
299// Evaluating castAs, getAs.
300//===----------------------------------------------------------------------===//
301
Csaba Dabis0202c352019-08-22 00:20:36 +0000302static void evalZeroParamNonNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000303 DefinedOrUnknownSVal DV,
304 CheckerContext &C,
305 bool IsCheckedCast = false) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000306 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
307 /*IsNonNullReturn=*/true, IsCheckedCast);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000308}
309
Csaba Dabis0202c352019-08-22 00:20:36 +0000310static void evalZeroParamNullReturn(const CallEvent &Call,
311 DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000312 CheckerContext &C) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000313 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
314 /*IsNonNullReturn=*/false);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000315}
316
Csaba Dabis0202c352019-08-22 00:20:36 +0000317void CastValueChecker::evalCastAs(const CallEvent &Call,
318 DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000319 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000320 evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000321}
322
Csaba Dabis0202c352019-08-22 00:20:36 +0000323void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000324 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000325 evalZeroParamNonNullReturn(Call, DV, C);
326 evalZeroParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000327}
328
Csaba Dabis0202c352019-08-22 00:20:36 +0000329//===----------------------------------------------------------------------===//
Csaba Dabis4d716002019-08-22 02:57:59 +0000330// Evaluating isa, isa_and_nonnull.
331//===----------------------------------------------------------------------===//
332
333void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
334 CheckerContext &C) const {
335 ProgramStateRef NonNullState, NullState;
336 std::tie(NonNullState, NullState) = C.getState()->assume(DV);
337
338 if (NonNullState) {
339 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
340 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
341 }
342
343 if (NullState) {
344 C.generateSink(NullState, C.getPredecessor());
345 }
346}
347
348void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call,
349 DefinedOrUnknownSVal DV,
350 CheckerContext &C) const {
351 ProgramStateRef NonNullState, NullState;
352 std::tie(NonNullState, NullState) = C.getState()->assume(DV);
353
354 if (NonNullState) {
355 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
356 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
357 }
358
359 if (NullState) {
360 addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false);
361 }
362}
363
364//===----------------------------------------------------------------------===//
Csaba Dabis0202c352019-08-22 00:20:36 +0000365// Main logic to evaluate a call.
366//===----------------------------------------------------------------------===//
367
Csaba Dabis693936a2019-07-10 00:20:03 +0000368bool CastValueChecker::evalCall(const CallEvent &Call,
369 CheckerContext &C) const {
Csaba Dabiscf229d52019-08-09 02:24:42 +0000370 const auto *Lookup = CDM.lookup(Call);
371 if (!Lookup)
Csaba Dabis693936a2019-07-10 00:20:03 +0000372 return false;
373
Csaba Dabiscf229d52019-08-09 02:24:42 +0000374 const CastCheck &Check = Lookup->first;
Csaba Dabis0202c352019-08-22 00:20:36 +0000375 CallKind Kind = Lookup->second;
Csaba Dabis4d716002019-08-22 02:57:59 +0000376
377 // We need to obtain the record type of the call's result to model it.
378 if (Kind != CallKind::InstanceOf &&
379 !getRecordType(Call.getResultType())->isRecordType())
380 return false;
381
Csaba Dabiscf229d52019-08-09 02:24:42 +0000382 Optional<DefinedOrUnknownSVal> DV;
383
384 switch (Kind) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000385 case CallKind::Function: {
386 // We need to obtain the record type of the call's parameter to model it.
387 if (!getRecordType(Call.parameters()[0]->getType())->isRecordType())
Csaba Dabiscf229d52019-08-09 02:24:42 +0000388 return false;
389
390 DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
391 break;
392 }
Csaba Dabis4d716002019-08-22 02:57:59 +0000393 case CallKind::InstanceOf: {
394 // We need to obtain the only template argument to determinte the type.
395 const FunctionDecl *FD = Call.getDecl()->getAsFunction();
396 if (!FD || !FD->getTemplateSpecializationArgs())
397 return false;
398
399 DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
400 break;
401 }
Csaba Dabis0202c352019-08-22 00:20:36 +0000402 case CallKind::Method:
Csaba Dabiscf229d52019-08-09 02:24:42 +0000403 const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call);
404 if (!InstanceCall)
405 return false;
406
407 DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>();
408 break;
409 }
410
411 if (!DV)
Csaba Dabis693936a2019-07-10 00:20:03 +0000412 return false;
413
Csaba Dabis0202c352019-08-22 00:20:36 +0000414 Check(this, Call, *DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000415 return true;
416}
417
Csaba Dabis0202c352019-08-22 00:20:36 +0000418void CastValueChecker::checkDeadSymbols(SymbolReaper &SR,
419 CheckerContext &C) const {
420 C.addTransition(removeDeadCasts(C.getState(), SR));
421}
422
Csaba Dabis693936a2019-07-10 00:20:03 +0000423void ento::registerCastValueChecker(CheckerManager &Mgr) {
424 Mgr.registerChecker<CastValueChecker>();
425}
426
427bool ento::shouldRegisterCastValueChecker(const LangOptions &LO) {
428 return true;
429}