blob: cd3b70db9a5f4bf991f02d8334f9b462f31f3936 [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;
54
55private:
Csaba Dabiscf229d52019-08-09 02:24:42 +000056 // These are known in the LLVM project. The pairs are in the following form:
57 // {{{namespace, call}, argument-count}, {callback, kind}}
Csaba Dabis0202c352019-08-22 00:20:36 +000058 const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = {
Csaba Dabiscf229d52019-08-09 02:24:42 +000059 {{{"llvm", "cast"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000060 {&CastValueChecker::evalCast, CallKind::Function}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000061 {{{"llvm", "dyn_cast"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000062 {&CastValueChecker::evalDynCast, CallKind::Function}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000063 {{{"llvm", "cast_or_null"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000064 {&CastValueChecker::evalCastOrNull, CallKind::Function}},
Csaba Dabis693936a2019-07-10 00:20:03 +000065 {{{"llvm", "dyn_cast_or_null"}, 1},
Csaba Dabis0202c352019-08-22 00:20:36 +000066 {&CastValueChecker::evalDynCastOrNull, CallKind::Function}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000067 {{{"clang", "castAs"}, 0},
Csaba Dabis0202c352019-08-22 00:20:36 +000068 {&CastValueChecker::evalCastAs, CallKind::Method}},
Csaba Dabiscf229d52019-08-09 02:24:42 +000069 {{{"clang", "getAs"}, 0},
Csaba Dabis4d716002019-08-22 02:57:59 +000070 {&CastValueChecker::evalGetAs, CallKind::Method}},
71 {{{"llvm", "isa"}, 1},
72 {&CastValueChecker::evalIsa, CallKind::InstanceOf}},
73 {{{"llvm", "isa_and_nonnull"}, 1},
74 {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};
Csaba Dabis693936a2019-07-10 00:20:03 +000075
Csaba Dabis0202c352019-08-22 00:20:36 +000076 void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000077 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000078 void evalDynCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000079 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000080 void evalCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000081 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000082 void evalDynCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +000083 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000084 void evalCastAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +000085 CheckerContext &C) const;
Csaba Dabis0202c352019-08-22 00:20:36 +000086 void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +000087 CheckerContext &C) const;
Csaba Dabis4d716002019-08-22 02:57:59 +000088 void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
89 CheckerContext &C) const;
90 void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
91 CheckerContext &C) const;
Csaba Dabis693936a2019-07-10 00:20:03 +000092};
93} // namespace
94
Csaba Dabis0202c352019-08-22 00:20:36 +000095static QualType getRecordType(QualType Ty) {
96 Ty = Ty.getCanonicalType();
Csaba Dabiscf229d52019-08-09 02:24:42 +000097
Csaba Dabis0202c352019-08-22 00:20:36 +000098 if (Ty->isPointerType())
99 Ty = Ty->getPointeeType();
100
101 if (Ty->isReferenceType())
102 Ty = Ty.getNonReferenceType();
103
104 return Ty.getUnqualifiedType();
Csaba Dabis693936a2019-07-10 00:20:03 +0000105}
106
Csaba Dabis0202c352019-08-22 00:20:36 +0000107static bool isInfeasibleCast(const DynamicCastInfo *CastInfo,
108 bool CastSucceeds) {
109 if (!CastInfo)
110 return false;
111
112 return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds();
113}
114
115static const NoteTag *getNoteTag(CheckerContext &C,
116 const DynamicCastInfo *CastInfo,
117 QualType CastToTy, const Expr *Object,
118 bool CastSucceeds, bool IsKnownCast) {
119 std::string CastToName =
120 CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString()
121 : CastToTy->getAsCXXRecordDecl()->getNameAsString();
122 Object = Object->IgnoreParenImpCasts();
Csaba Dabis693936a2019-07-10 00:20:03 +0000123
Csaba Dabiscf229d52019-08-09 02:24:42 +0000124 return C.getNoteTag(
Csaba Dabis22dc44f2019-08-22 01:41:06 +0000125 [=]() -> std::string {
Csaba Dabis693936a2019-07-10 00:20:03 +0000126 SmallString<128> Msg;
127 llvm::raw_svector_ostream Out(Msg);
128
Csaba Dabis0202c352019-08-22 00:20:36 +0000129 if (!IsKnownCast)
130 Out << "Assuming ";
Csaba Dabiscf229d52019-08-09 02:24:42 +0000131
Csaba Dabis0202c352019-08-22 00:20:36 +0000132 if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
133 Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
134 } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) {
135 Out << (IsKnownCast ? "Field '" : "field '")
136 << ME->getMemberDecl()->getNameAsString() << '\'';
137 } else {
138 Out << (IsKnownCast ? "The object" : "the object");
139 }
140
141 Out << ' ' << (CastSucceeds ? "is a" : "is not a") << " '" << CastToName
142 << '\'';
Csaba Dabiscf229d52019-08-09 02:24:42 +0000143
Csaba Dabis693936a2019-07-10 00:20:03 +0000144 return Out.str();
145 },
146 /*IsPrunable=*/true);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000147}
Csaba Dabis693936a2019-07-10 00:20:03 +0000148
Csaba Dabis0202c352019-08-22 00:20:36 +0000149//===----------------------------------------------------------------------===//
150// Main logic to evaluate a cast.
151//===----------------------------------------------------------------------===//
152
153static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV,
154 CheckerContext &C, bool IsNonNullParam,
155 bool IsNonNullReturn,
156 bool IsCheckedCast = false) {
157 ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam);
158 if (!State)
159 return;
160
161 const Expr *Object;
162 QualType CastFromTy;
163 QualType CastToTy = getRecordType(Call.getResultType());
164
165 if (Call.getNumArgs() > 0) {
166 Object = Call.getArgExpr(0);
167 CastFromTy = getRecordType(Call.parameters()[0]->getType());
168 } else {
169 Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
170 CastFromTy = getRecordType(Object->getType());
171 }
172
173 const MemRegion *MR = DV.getAsRegion();
174 const DynamicCastInfo *CastInfo =
175 getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
176
177 // We assume that every checked cast succeeds.
178 bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
179 if (!CastSucceeds) {
180 if (CastInfo)
181 CastSucceeds = IsNonNullReturn && CastInfo->succeeds();
182 else
183 CastSucceeds = IsNonNullReturn;
184 }
185
186 // Check for infeasible casts.
187 if (isInfeasibleCast(CastInfo, CastSucceeds)) {
188 C.generateSink(State, C.getPredecessor());
189 return;
190 }
191
192 // Store the type and the cast information.
193 bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
194 if (!IsKnownCast || IsCheckedCast)
195 State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
196 Call.getResultType(), CastSucceeds);
197
198 SVal V = CastSucceeds ? DV : C.getSValBuilder().makeNull();
199 C.addTransition(
200 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
201 getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
Csaba Dabiscf229d52019-08-09 02:24:42 +0000202}
203
Csaba Dabis4d716002019-08-22 02:57:59 +0000204static void addInstanceOfTransition(const CallEvent &Call,
205 DefinedOrUnknownSVal DV,
206 ProgramStateRef State, CheckerContext &C,
207 bool IsInstanceOf) {
208 const FunctionDecl *FD = Call.getDecl()->getAsFunction();
209 QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType();
210 QualType CastFromTy = getRecordType(Call.parameters()[0]->getType());
211
212 const MemRegion *MR = DV.getAsRegion();
213 const DynamicCastInfo *CastInfo =
214 getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
215
216 bool CastSucceeds;
217 if (CastInfo)
218 CastSucceeds = IsInstanceOf && CastInfo->succeeds();
219 else
220 CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
221
222 if (isInfeasibleCast(CastInfo, CastSucceeds)) {
223 C.generateSink(State, C.getPredecessor());
224 return;
225 }
226
227 // Store the type and the cast information.
228 bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
229 if (!IsKnownCast)
230 State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
231 Call.getResultType(), IsInstanceOf);
232
233 C.addTransition(
234 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
235 C.getSValBuilder().makeTruthVal(CastSucceeds)),
236 getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds,
237 IsKnownCast));
238}
239
Csaba Dabiscf229d52019-08-09 02:24:42 +0000240//===----------------------------------------------------------------------===//
241// Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null.
242//===----------------------------------------------------------------------===//
243
Csaba Dabis0202c352019-08-22 00:20:36 +0000244static void evalNonNullParamNonNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000245 DefinedOrUnknownSVal DV,
246 CheckerContext &C,
247 bool IsCheckedCast = false) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000248 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
249 /*IsNonNullReturn=*/true, IsCheckedCast);
Csaba Dabis693936a2019-07-10 00:20:03 +0000250}
251
Csaba Dabis0202c352019-08-22 00:20:36 +0000252static void evalNonNullParamNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000253 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000254 CheckerContext &C) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000255 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
256 /*IsNonNullReturn=*/false);
Csaba Dabis693936a2019-07-10 00:20:03 +0000257}
258
Csaba Dabis0202c352019-08-22 00:20:36 +0000259static void evalNullParamNullReturn(const CallEvent &Call,
260 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000261 CheckerContext &C) {
Csaba Dabiscf229d52019-08-09 02:24:42 +0000262 if (ProgramStateRef State = C.getState()->assume(DV, false))
Csaba Dabis0202c352019-08-22 00:20:36 +0000263 C.addTransition(State->BindExpr(Call.getOriginExpr(),
264 C.getLocationContext(),
265 C.getSValBuilder().makeNull(), false),
Csaba Dabiscf229d52019-08-09 02:24:42 +0000266 C.getNoteTag("Assuming null pointer is passed into cast",
267 /*IsPrunable=*/true));
Csaba Dabis693936a2019-07-10 00:20:03 +0000268}
269
Csaba Dabis0202c352019-08-22 00:20:36 +0000270void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000271 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000272 evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
Csaba Dabis693936a2019-07-10 00:20:03 +0000273}
274
Csaba Dabis0202c352019-08-22 00:20:36 +0000275void CastValueChecker::evalDynCast(const CallEvent &Call,
276 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000277 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000278 evalNonNullParamNonNullReturn(Call, DV, C);
279 evalNonNullParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000280}
281
Csaba Dabis0202c352019-08-22 00:20:36 +0000282void CastValueChecker::evalCastOrNull(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000283 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000284 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000285 evalNonNullParamNonNullReturn(Call, DV, C);
286 evalNullParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000287}
288
Csaba Dabis0202c352019-08-22 00:20:36 +0000289void CastValueChecker::evalDynCastOrNull(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000290 DefinedOrUnknownSVal DV,
Csaba Dabis693936a2019-07-10 00:20:03 +0000291 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000292 evalNonNullParamNonNullReturn(Call, DV, C);
293 evalNonNullParamNullReturn(Call, DV, C);
294 evalNullParamNullReturn(Call, DV, C);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000295}
296
297//===----------------------------------------------------------------------===//
298// Evaluating castAs, getAs.
299//===----------------------------------------------------------------------===//
300
Csaba Dabis0202c352019-08-22 00:20:36 +0000301static void evalZeroParamNonNullReturn(const CallEvent &Call,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000302 DefinedOrUnknownSVal DV,
303 CheckerContext &C,
304 bool IsCheckedCast = false) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000305 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
306 /*IsNonNullReturn=*/true, IsCheckedCast);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000307}
308
Csaba Dabis0202c352019-08-22 00:20:36 +0000309static void evalZeroParamNullReturn(const CallEvent &Call,
310 DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000311 CheckerContext &C) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000312 addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
313 /*IsNonNullReturn=*/false);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000314}
315
Csaba Dabis0202c352019-08-22 00:20:36 +0000316void CastValueChecker::evalCastAs(const CallEvent &Call,
317 DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000318 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000319 evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
Csaba Dabiscf229d52019-08-09 02:24:42 +0000320}
321
Csaba Dabis0202c352019-08-22 00:20:36 +0000322void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
Csaba Dabiscf229d52019-08-09 02:24:42 +0000323 CheckerContext &C) const {
Csaba Dabis0202c352019-08-22 00:20:36 +0000324 evalZeroParamNonNullReturn(Call, DV, C);
325 evalZeroParamNullReturn(Call, DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000326}
327
Csaba Dabis0202c352019-08-22 00:20:36 +0000328//===----------------------------------------------------------------------===//
Csaba Dabis4d716002019-08-22 02:57:59 +0000329// Evaluating isa, isa_and_nonnull.
330//===----------------------------------------------------------------------===//
331
332void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
333 CheckerContext &C) const {
334 ProgramStateRef NonNullState, NullState;
335 std::tie(NonNullState, NullState) = C.getState()->assume(DV);
336
337 if (NonNullState) {
338 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
339 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
340 }
341
342 if (NullState) {
343 C.generateSink(NullState, C.getPredecessor());
344 }
345}
346
347void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call,
348 DefinedOrUnknownSVal DV,
349 CheckerContext &C) const {
350 ProgramStateRef NonNullState, NullState;
351 std::tie(NonNullState, NullState) = C.getState()->assume(DV);
352
353 if (NonNullState) {
354 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
355 addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
356 }
357
358 if (NullState) {
359 addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false);
360 }
361}
362
363//===----------------------------------------------------------------------===//
Csaba Dabis0202c352019-08-22 00:20:36 +0000364// Main logic to evaluate a call.
365//===----------------------------------------------------------------------===//
366
Csaba Dabis693936a2019-07-10 00:20:03 +0000367bool CastValueChecker::evalCall(const CallEvent &Call,
368 CheckerContext &C) const {
Csaba Dabiscf229d52019-08-09 02:24:42 +0000369 const auto *Lookup = CDM.lookup(Call);
370 if (!Lookup)
Csaba Dabis693936a2019-07-10 00:20:03 +0000371 return false;
372
Csaba Dabiscf229d52019-08-09 02:24:42 +0000373 const CastCheck &Check = Lookup->first;
Csaba Dabis0202c352019-08-22 00:20:36 +0000374 CallKind Kind = Lookup->second;
Csaba Dabis4d716002019-08-22 02:57:59 +0000375
376 // We need to obtain the record type of the call's result to model it.
377 if (Kind != CallKind::InstanceOf &&
378 !getRecordType(Call.getResultType())->isRecordType())
379 return false;
380
Csaba Dabiscf229d52019-08-09 02:24:42 +0000381 Optional<DefinedOrUnknownSVal> DV;
382
383 switch (Kind) {
Csaba Dabis0202c352019-08-22 00:20:36 +0000384 case CallKind::Function: {
Artem Dergachevaf992e62019-08-23 03:23:58 +0000385 // We only model casts from pointers to pointers or from references
386 // to references. Other casts are most likely specialized and we
387 // cannot model them.
388 QualType ParamT = Call.parameters()[0]->getType();
389 QualType ResultT = Call.getResultType();
390 if (!(ParamT->isPointerType() && ResultT->isPointerType()) &&
391 !(ParamT->isReferenceType() && ResultT->isReferenceType()))
Csaba Dabiscf229d52019-08-09 02:24:42 +0000392 return false;
393
394 DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
395 break;
396 }
Csaba Dabis4d716002019-08-22 02:57:59 +0000397 case CallKind::InstanceOf: {
398 // We need to obtain the only template argument to determinte the type.
399 const FunctionDecl *FD = Call.getDecl()->getAsFunction();
400 if (!FD || !FD->getTemplateSpecializationArgs())
401 return false;
402
403 DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
404 break;
405 }
Csaba Dabis0202c352019-08-22 00:20:36 +0000406 case CallKind::Method:
Csaba Dabiscf229d52019-08-09 02:24:42 +0000407 const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call);
408 if (!InstanceCall)
409 return false;
410
411 DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>();
412 break;
413 }
414
415 if (!DV)
Csaba Dabis693936a2019-07-10 00:20:03 +0000416 return false;
417
Csaba Dabis0202c352019-08-22 00:20:36 +0000418 Check(this, Call, *DV, C);
Csaba Dabis693936a2019-07-10 00:20:03 +0000419 return true;
420}
421
Csaba Dabis693936a2019-07-10 00:20:03 +0000422void ento::registerCastValueChecker(CheckerManager &Mgr) {
423 Mgr.registerChecker<CastValueChecker>();
424}
425
426bool ento::shouldRegisterCastValueChecker(const LangOptions &LO) {
427 return true;
428}