1159024ceSValeriy Savchenko //===- unittests/StaticAnalyzer/SvalTest.cpp ------------------------------===//
2159024ceSValeriy Savchenko //
3159024ceSValeriy Savchenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4159024ceSValeriy Savchenko // See https://llvm.org/LICENSE.txt for license information.
5159024ceSValeriy Savchenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6159024ceSValeriy Savchenko //
7159024ceSValeriy Savchenko //===----------------------------------------------------------------------===//
8159024ceSValeriy Savchenko
9159024ceSValeriy Savchenko #include "CheckerRegistration.h"
10159024ceSValeriy Savchenko
11159024ceSValeriy Savchenko #include "clang/AST/ASTContext.h"
12159024ceSValeriy Savchenko #include "clang/AST/Decl.h"
13159024ceSValeriy Savchenko #include "clang/AST/DeclGroup.h"
14159024ceSValeriy Savchenko #include "clang/AST/RecursiveASTVisitor.h"
15159024ceSValeriy Savchenko #include "clang/AST/Stmt.h"
16159024ceSValeriy Savchenko #include "clang/AST/Type.h"
17159024ceSValeriy Savchenko #include "clang/StaticAnalyzer/Core/Checker.h"
18159024ceSValeriy Savchenko #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19159024ceSValeriy Savchenko #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
20159024ceSValeriy Savchenko #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
21159024ceSValeriy Savchenko #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
22159024ceSValeriy Savchenko #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
23159024ceSValeriy Savchenko #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
249c4d194fSSteven Wan #include "clang/Testing/TestClangConfig.h"
25159024ceSValeriy Savchenko #include "clang/Tooling/Tooling.h"
26159024ceSValeriy Savchenko #include "llvm/ADT/STLExtras.h"
27159024ceSValeriy Savchenko #include "llvm/ADT/StringRef.h"
28159024ceSValeriy Savchenko #include "llvm/Support/Casting.h"
29159024ceSValeriy Savchenko #include "llvm/Support/raw_ostream.h"
30159024ceSValeriy Savchenko #include "gtest/gtest.h"
31159024ceSValeriy Savchenko
32159024ceSValeriy Savchenko namespace clang {
33159024ceSValeriy Savchenko
34159024ceSValeriy Savchenko // getType() tests include whole bunch of type comparisons,
35159024ceSValeriy Savchenko // so when something is wrong, it's good to have gtest telling us
36159024ceSValeriy Savchenko // what are those types.
operator <<(std::ostream & OS,const QualType & T)37159024ceSValeriy Savchenko LLVM_ATTRIBUTE_UNUSED std::ostream &operator<<(std::ostream &OS,
38159024ceSValeriy Savchenko const QualType &T) {
39159024ceSValeriy Savchenko return OS << T.getAsString();
40159024ceSValeriy Savchenko }
41159024ceSValeriy Savchenko
operator <<(std::ostream & OS,const CanQualType & T)42159024ceSValeriy Savchenko LLVM_ATTRIBUTE_UNUSED std::ostream &operator<<(std::ostream &OS,
43159024ceSValeriy Savchenko const CanQualType &T) {
44159024ceSValeriy Savchenko return OS << QualType{T};
45159024ceSValeriy Savchenko }
46159024ceSValeriy Savchenko
47159024ceSValeriy Savchenko namespace ento {
48159024ceSValeriy Savchenko namespace {
49159024ceSValeriy Savchenko
50159024ceSValeriy Savchenko //===----------------------------------------------------------------------===//
51159024ceSValeriy Savchenko // Testing framework implementation
52159024ceSValeriy Savchenko //===----------------------------------------------------------------------===//
53159024ceSValeriy Savchenko
54159024ceSValeriy Savchenko /// A simple map from variable names to symbolic values used to init them.
55159024ceSValeriy Savchenko using SVals = llvm::StringMap<SVal>;
56159024ceSValeriy Savchenko
57159024ceSValeriy Savchenko /// SValCollector is the barebone of all tests.
58159024ceSValeriy Savchenko ///
59159024ceSValeriy Savchenko /// It is implemented as a checker and reacts to binds, so we find
60159024ceSValeriy Savchenko /// symbolic values of interest, and to end analysis, where we actually
61159024ceSValeriy Savchenko /// can test whatever we gathered.
62159024ceSValeriy Savchenko class SValCollector : public Checker<check::Bind, check::EndAnalysis> {
63159024ceSValeriy Savchenko public:
checkBind(SVal Loc,SVal Val,const Stmt * S,CheckerContext & C) const64159024ceSValeriy Savchenko void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {
65159024ceSValeriy Savchenko // Skip instantly if we finished testing.
66159024ceSValeriy Savchenko // Also, we care only for binds happening in variable initializations.
67159024ceSValeriy Savchenko if (Tested || !isa<DeclStmt>(S))
68159024ceSValeriy Savchenko return;
69159024ceSValeriy Savchenko
70159024ceSValeriy Savchenko if (const auto *VR = llvm::dyn_cast_or_null<VarRegion>(Loc.getAsRegion())) {
71159024ceSValeriy Savchenko CollectedSVals[VR->getDescriptiveName(false)] = Val;
72159024ceSValeriy Savchenko }
73159024ceSValeriy Savchenko }
74159024ceSValeriy Savchenko
checkEndAnalysis(ExplodedGraph & G,BugReporter & B,ExprEngine & Engine) const75159024ceSValeriy Savchenko void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,
76159024ceSValeriy Savchenko ExprEngine &Engine) const {
77159024ceSValeriy Savchenko if (!Tested) {
78159024ceSValeriy Savchenko test(Engine, Engine.getContext());
79159024ceSValeriy Savchenko Tested = true;
80159024ceSValeriy Savchenko CollectedSVals.clear();
81159024ceSValeriy Savchenko }
82159024ceSValeriy Savchenko }
83159024ceSValeriy Savchenko
84159024ceSValeriy Savchenko /// Helper function for tests to access bound symbolic values.
getByName(StringRef Name) const85159024ceSValeriy Savchenko SVal getByName(StringRef Name) const { return CollectedSVals[Name]; }
86159024ceSValeriy Savchenko
87159024ceSValeriy Savchenko private:
88159024ceSValeriy Savchenko /// Entry point for tests.
89159024ceSValeriy Savchenko virtual void test(ExprEngine &Engine, const ASTContext &Context) const = 0;
90159024ceSValeriy Savchenko
91159024ceSValeriy Savchenko mutable bool Tested = false;
92159024ceSValeriy Savchenko mutable SVals CollectedSVals;
93159024ceSValeriy Savchenko };
94159024ceSValeriy Savchenko
expectSameSignAndBitWidth(QualType ExpectedTy,QualType ActualTy,const ASTContext & Context)95881b6a00SBalazs Benics static void expectSameSignAndBitWidth(QualType ExpectedTy, QualType ActualTy,
96881b6a00SBalazs Benics const ASTContext &Context) {
97881b6a00SBalazs Benics EXPECT_EQ(ExpectedTy->isUnsignedIntegerType(),
98881b6a00SBalazs Benics ActualTy->isUnsignedIntegerType());
99881b6a00SBalazs Benics EXPECT_EQ(Context.getTypeSize(ExpectedTy), Context.getTypeSize(ActualTy));
1009c4d194fSSteven Wan }
101881b6a00SBalazs Benics
102881b6a00SBalazs Benics // Fixture class for parameterized SValTest
103881b6a00SBalazs Benics class SValTest : public testing::TestWithParam<TestClangConfig> {};
1049c4d194fSSteven Wan
105159024ceSValeriy Savchenko // SVAL_TEST is a combined way of providing a short code snippet and
106159024ceSValeriy Savchenko // to test some programmatic predicates on symbolic values produced by the
107159024ceSValeriy Savchenko // engine for the actual code.
108159024ceSValeriy Savchenko //
109159024ceSValeriy Savchenko // Each test has a NAME. One can think of it as a name for normal gtests.
110159024ceSValeriy Savchenko //
111159024ceSValeriy Savchenko // Each test should provide a CODE snippet. Code snippets might contain any
112159024ceSValeriy Savchenko // valid C/C++, but have ONLY ONE defined function. There are no requirements
113159024ceSValeriy Savchenko // about function's name or parameters. It can even be a class method. The
114159024ceSValeriy Savchenko // body of the function must contain a set of variable declarations. Each
115159024ceSValeriy Savchenko // variable declaration gets bound to a symbolic value, so for the following
116159024ceSValeriy Savchenko // example:
117159024ceSValeriy Savchenko //
118159024ceSValeriy Savchenko // int x = <expr>;
119159024ceSValeriy Savchenko //
120159024ceSValeriy Savchenko // `x` will be bound to whatever symbolic value the engine produced for <expr>.
121159024ceSValeriy Savchenko // LIVENESS and REASSIGNMENTS don't affect this binding.
122159024ceSValeriy Savchenko //
123159024ceSValeriy Savchenko // During the test the actual values can be accessed via `getByName` function,
124159024ceSValeriy Savchenko // and, for the `x`-bound value, one must use "x" as its name.
125159024ceSValeriy Savchenko //
126159024ceSValeriy Savchenko // Example:
127159024ceSValeriy Savchenko // SVAL_TEST(SimpleSValTest, R"(
128159024ceSValeriy Savchenko // void foo() {
129159024ceSValeriy Savchenko // int x = 42;
130159024ceSValeriy Savchenko // })") {
131159024ceSValeriy Savchenko // SVal X = getByName("x");
132159024ceSValeriy Savchenko // EXPECT_TRUE(X.isConstant(42));
133159024ceSValeriy Savchenko // }
134159024ceSValeriy Savchenko #define SVAL_TEST(NAME, CODE) \
135159024ceSValeriy Savchenko class NAME##SValCollector final : public SValCollector { \
136159024ceSValeriy Savchenko public: \
137159024ceSValeriy Savchenko void test(ExprEngine &Engine, const ASTContext &Context) const override; \
138159024ceSValeriy Savchenko }; \
139159024ceSValeriy Savchenko \
140159024ceSValeriy Savchenko void add##NAME##SValCollector(AnalysisASTConsumer &AnalysisConsumer, \
141159024ceSValeriy Savchenko AnalyzerOptions &AnOpts) { \
142159024ceSValeriy Savchenko AnOpts.CheckersAndPackages = {{"test.##NAME##SValCollector", true}}; \
143159024ceSValeriy Savchenko AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { \
144159024ceSValeriy Savchenko Registry.addChecker<NAME##SValCollector>("test.##NAME##SValCollector", \
145159024ceSValeriy Savchenko "Description", ""); \
146159024ceSValeriy Savchenko }); \
147159024ceSValeriy Savchenko } \
148159024ceSValeriy Savchenko \
1499c4d194fSSteven Wan TEST_P(SValTest, NAME) { \
150881b6a00SBalazs Benics EXPECT_TRUE(runCheckerOnCodeWithArgs<add##NAME##SValCollector>( \
151881b6a00SBalazs Benics CODE, GetParam().getCommandLineArgs())); \
1529c4d194fSSteven Wan } \
153159024ceSValeriy Savchenko void NAME##SValCollector::test(ExprEngine &Engine, \
154159024ceSValeriy Savchenko const ASTContext &Context) const
155159024ceSValeriy Savchenko
156159024ceSValeriy Savchenko //===----------------------------------------------------------------------===//
157159024ceSValeriy Savchenko // Actual tests
158159024ceSValeriy Savchenko //===----------------------------------------------------------------------===//
159159024ceSValeriy Savchenko
160159024ceSValeriy Savchenko SVAL_TEST(GetConstType, R"(
161159024ceSValeriy Savchenko void foo() {
162159024ceSValeriy Savchenko int x = 42;
163159024ceSValeriy Savchenko int *y = nullptr;
16432fe1a4bSElla Ma bool z = true;
165159024ceSValeriy Savchenko })") {
166159024ceSValeriy Savchenko SVal X = getByName("x");
167159024ceSValeriy Savchenko ASSERT_FALSE(X.getType(Context).isNull());
168159024ceSValeriy Savchenko EXPECT_EQ(Context.IntTy, X.getType(Context));
169159024ceSValeriy Savchenko
170159024ceSValeriy Savchenko SVal Y = getByName("y");
171159024ceSValeriy Savchenko ASSERT_FALSE(Y.getType(Context).isNull());
172881b6a00SBalazs Benics expectSameSignAndBitWidth(Context.getUIntPtrType(), Y.getType(Context),
173881b6a00SBalazs Benics Context);
17432fe1a4bSElla Ma
17532fe1a4bSElla Ma SVal Z = getByName("z");
17632fe1a4bSElla Ma ASSERT_FALSE(Z.getType(Context).isNull());
17732fe1a4bSElla Ma EXPECT_EQ(Context.BoolTy, Z.getType(Context));
178159024ceSValeriy Savchenko }
179159024ceSValeriy Savchenko
180159024ceSValeriy Savchenko SVAL_TEST(GetLocAsIntType, R"(
181159024ceSValeriy Savchenko void foo(int *x) {
182881b6a00SBalazs Benics long int a = (long long int)x;
183881b6a00SBalazs Benics unsigned b = (long long unsigned)&a;
184881b6a00SBalazs Benics int c = (long long int)nullptr;
185159024ceSValeriy Savchenko })") {
186159024ceSValeriy Savchenko SVal A = getByName("a");
187159024ceSValeriy Savchenko ASSERT_FALSE(A.getType(Context).isNull());
188881b6a00SBalazs Benics
189159024ceSValeriy Savchenko // TODO: Turn it into signed long
190881b6a00SBalazs Benics expectSameSignAndBitWidth(Context.UnsignedLongTy, A.getType(Context),
191881b6a00SBalazs Benics Context);
192159024ceSValeriy Savchenko
193159024ceSValeriy Savchenko SVal B = getByName("b");
194159024ceSValeriy Savchenko ASSERT_FALSE(B.getType(Context).isNull());
195881b6a00SBalazs Benics expectSameSignAndBitWidth(Context.UnsignedIntTy, B.getType(Context), Context);
196159024ceSValeriy Savchenko
197159024ceSValeriy Savchenko SVal C = getByName("c");
198159024ceSValeriy Savchenko ASSERT_FALSE(C.getType(Context).isNull());
199881b6a00SBalazs Benics expectSameSignAndBitWidth(Context.IntTy, C.getType(Context), Context);
200159024ceSValeriy Savchenko }
201159024ceSValeriy Savchenko
202159024ceSValeriy Savchenko SVAL_TEST(GetSymExprType, R"(
203159024ceSValeriy Savchenko void foo(int a, int b) {
204159024ceSValeriy Savchenko int x = a;
205159024ceSValeriy Savchenko int y = a + b;
206159024ceSValeriy Savchenko long z = a;
207159024ceSValeriy Savchenko })") {
208159024ceSValeriy Savchenko QualType Int = Context.IntTy;
209159024ceSValeriy Savchenko
210159024ceSValeriy Savchenko SVal X = getByName("x");
211159024ceSValeriy Savchenko ASSERT_FALSE(X.getType(Context).isNull());
212159024ceSValeriy Savchenko EXPECT_EQ(Int, X.getType(Context));
213159024ceSValeriy Savchenko
214159024ceSValeriy Savchenko SVal Y = getByName("y");
215159024ceSValeriy Savchenko ASSERT_FALSE(Y.getType(Context).isNull());
216159024ceSValeriy Savchenko EXPECT_EQ(Int, Y.getType(Context));
217159024ceSValeriy Savchenko
218159024ceSValeriy Savchenko // TODO: Change to Long when we support symbolic casts
219159024ceSValeriy Savchenko SVal Z = getByName("z");
220159024ceSValeriy Savchenko ASSERT_FALSE(Z.getType(Context).isNull());
221159024ceSValeriy Savchenko EXPECT_EQ(Int, Z.getType(Context));
222159024ceSValeriy Savchenko }
223159024ceSValeriy Savchenko
224159024ceSValeriy Savchenko SVAL_TEST(GetPointerType, R"(
225159024ceSValeriy Savchenko int *bar();
226159024ceSValeriy Savchenko int &foobar();
227159024ceSValeriy Savchenko struct Z {
228159024ceSValeriy Savchenko int a;
229159024ceSValeriy Savchenko int *b;
230159024ceSValeriy Savchenko };
231159024ceSValeriy Savchenko void foo(int x, int *y, Z z) {
232159024ceSValeriy Savchenko int &a = x;
233159024ceSValeriy Savchenko int &b = *y;
234159024ceSValeriy Savchenko int &c = *bar();
235159024ceSValeriy Savchenko int &d = foobar();
236159024ceSValeriy Savchenko int &e = z.a;
237159024ceSValeriy Savchenko int &f = *z.b;
238159024ceSValeriy Savchenko })") {
239159024ceSValeriy Savchenko QualType Int = Context.IntTy;
240159024ceSValeriy Savchenko
241159024ceSValeriy Savchenko SVal A = getByName("a");
242159024ceSValeriy Savchenko ASSERT_FALSE(A.getType(Context).isNull());
243159024ceSValeriy Savchenko const auto *APtrTy = dyn_cast<PointerType>(A.getType(Context));
244159024ceSValeriy Savchenko ASSERT_NE(APtrTy, nullptr);
245159024ceSValeriy Savchenko EXPECT_EQ(Int, APtrTy->getPointeeType());
246159024ceSValeriy Savchenko
247159024ceSValeriy Savchenko SVal B = getByName("b");
248159024ceSValeriy Savchenko ASSERT_FALSE(B.getType(Context).isNull());
249159024ceSValeriy Savchenko const auto *BPtrTy = dyn_cast<PointerType>(B.getType(Context));
250159024ceSValeriy Savchenko ASSERT_NE(BPtrTy, nullptr);
251159024ceSValeriy Savchenko EXPECT_EQ(Int, BPtrTy->getPointeeType());
252159024ceSValeriy Savchenko
253159024ceSValeriy Savchenko SVal C = getByName("c");
254159024ceSValeriy Savchenko ASSERT_FALSE(C.getType(Context).isNull());
255159024ceSValeriy Savchenko const auto *CPtrTy = dyn_cast<PointerType>(C.getType(Context));
256159024ceSValeriy Savchenko ASSERT_NE(CPtrTy, nullptr);
257159024ceSValeriy Savchenko EXPECT_EQ(Int, CPtrTy->getPointeeType());
258159024ceSValeriy Savchenko
259159024ceSValeriy Savchenko SVal D = getByName("d");
260159024ceSValeriy Savchenko ASSERT_FALSE(D.getType(Context).isNull());
261159024ceSValeriy Savchenko const auto *DRefTy = dyn_cast<LValueReferenceType>(D.getType(Context));
262159024ceSValeriy Savchenko ASSERT_NE(DRefTy, nullptr);
263159024ceSValeriy Savchenko EXPECT_EQ(Int, DRefTy->getPointeeType());
264159024ceSValeriy Savchenko
265159024ceSValeriy Savchenko SVal E = getByName("e");
266159024ceSValeriy Savchenko ASSERT_FALSE(E.getType(Context).isNull());
267159024ceSValeriy Savchenko const auto *EPtrTy = dyn_cast<PointerType>(E.getType(Context));
268159024ceSValeriy Savchenko ASSERT_NE(EPtrTy, nullptr);
269159024ceSValeriy Savchenko EXPECT_EQ(Int, EPtrTy->getPointeeType());
270159024ceSValeriy Savchenko
271159024ceSValeriy Savchenko SVal F = getByName("f");
272159024ceSValeriy Savchenko ASSERT_FALSE(F.getType(Context).isNull());
273159024ceSValeriy Savchenko const auto *FPtrTy = dyn_cast<PointerType>(F.getType(Context));
274159024ceSValeriy Savchenko ASSERT_NE(FPtrTy, nullptr);
275159024ceSValeriy Savchenko EXPECT_EQ(Int, FPtrTy->getPointeeType());
276159024ceSValeriy Savchenko }
277159024ceSValeriy Savchenko
278159024ceSValeriy Savchenko SVAL_TEST(GetCompoundType, R"(
279159024ceSValeriy Savchenko struct TestStruct {
280159024ceSValeriy Savchenko int a, b;
281159024ceSValeriy Savchenko };
282159024ceSValeriy Savchenko union TestUnion {
283159024ceSValeriy Savchenko int a;
284159024ceSValeriy Savchenko float b;
285159024ceSValeriy Savchenko TestStruct c;
286159024ceSValeriy Savchenko };
287159024ceSValeriy Savchenko void foo(int x) {
288159024ceSValeriy Savchenko int a[] = {1, x, 2};
289159024ceSValeriy Savchenko TestStruct b = {x, 42};
290159024ceSValeriy Savchenko TestUnion c = {42};
291159024ceSValeriy Savchenko TestUnion d = {.c=b};
292159024ceSValeriy Savchenko }
293159024ceSValeriy Savchenko )") {
294159024ceSValeriy Savchenko SVal A = getByName("a");
295159024ceSValeriy Savchenko ASSERT_FALSE(A.getType(Context).isNull());
296159024ceSValeriy Savchenko const auto *AArrayType = dyn_cast<ArrayType>(A.getType(Context));
297159024ceSValeriy Savchenko ASSERT_NE(AArrayType, nullptr);
298159024ceSValeriy Savchenko EXPECT_EQ(Context.IntTy, AArrayType->getElementType());
299159024ceSValeriy Savchenko
300159024ceSValeriy Savchenko SVal B = getByName("b");
301159024ceSValeriy Savchenko ASSERT_FALSE(B.getType(Context).isNull());
302159024ceSValeriy Savchenko const auto *BRecordType = dyn_cast<RecordType>(B.getType(Context));
303159024ceSValeriy Savchenko ASSERT_NE(BRecordType, nullptr);
304159024ceSValeriy Savchenko EXPECT_EQ("TestStruct", BRecordType->getDecl()->getName());
305159024ceSValeriy Savchenko
306159024ceSValeriy Savchenko SVal C = getByName("c");
307159024ceSValeriy Savchenko ASSERT_FALSE(C.getType(Context).isNull());
308159024ceSValeriy Savchenko const auto *CRecordType = dyn_cast<RecordType>(C.getType(Context));
309159024ceSValeriy Savchenko ASSERT_NE(CRecordType, nullptr);
310159024ceSValeriy Savchenko EXPECT_EQ("TestUnion", CRecordType->getDecl()->getName());
311159024ceSValeriy Savchenko
312159024ceSValeriy Savchenko auto D = getByName("d").getAs<nonloc::CompoundVal>();
31353daa177SKazu Hirata ASSERT_TRUE(D.has_value());
314159024ceSValeriy Savchenko auto Begin = D->begin();
315159024ceSValeriy Savchenko ASSERT_NE(D->end(), Begin);
316159024ceSValeriy Savchenko ++Begin;
317159024ceSValeriy Savchenko ASSERT_EQ(D->end(), Begin);
318159024ceSValeriy Savchenko auto LD = D->begin()->getAs<nonloc::LazyCompoundVal>();
31953daa177SKazu Hirata ASSERT_TRUE(LD.has_value());
320159024ceSValeriy Savchenko auto LDT = LD->getType(Context);
321159024ceSValeriy Savchenko ASSERT_FALSE(LDT.isNull());
322*15f3cd6bSMatheus Izvekov const auto *DElaboratedType = dyn_cast<ElaboratedType>(LDT);
323*15f3cd6bSMatheus Izvekov ASSERT_NE(DElaboratedType, nullptr);
324*15f3cd6bSMatheus Izvekov const auto *DRecordType =
325*15f3cd6bSMatheus Izvekov dyn_cast<RecordType>(DElaboratedType->getNamedType());
326159024ceSValeriy Savchenko ASSERT_NE(DRecordType, nullptr);
327159024ceSValeriy Savchenko EXPECT_EQ("TestStruct", DRecordType->getDecl()->getName());
328159024ceSValeriy Savchenko }
329159024ceSValeriy Savchenko
330159024ceSValeriy Savchenko SVAL_TEST(GetStringType, R"(
331159024ceSValeriy Savchenko void foo() {
332159024ceSValeriy Savchenko const char *a = "Hello, world!";
333159024ceSValeriy Savchenko }
334159024ceSValeriy Savchenko )") {
335159024ceSValeriy Savchenko SVal A = getByName("a");
336159024ceSValeriy Savchenko ASSERT_FALSE(A.getType(Context).isNull());
337159024ceSValeriy Savchenko const auto *APtrTy = dyn_cast<PointerType>(A.getType(Context));
338159024ceSValeriy Savchenko ASSERT_NE(APtrTy, nullptr);
339159024ceSValeriy Savchenko EXPECT_EQ(Context.CharTy, APtrTy->getPointeeType());
340159024ceSValeriy Savchenko }
341159024ceSValeriy Savchenko
342159024ceSValeriy Savchenko SVAL_TEST(GetThisType, R"(
343159024ceSValeriy Savchenko class TestClass {
344159024ceSValeriy Savchenko void foo();
345159024ceSValeriy Savchenko };
346159024ceSValeriy Savchenko void TestClass::foo() {
347159024ceSValeriy Savchenko const auto *a = this;
348159024ceSValeriy Savchenko }
349159024ceSValeriy Savchenko )") {
350159024ceSValeriy Savchenko SVal A = getByName("a");
351159024ceSValeriy Savchenko ASSERT_FALSE(A.getType(Context).isNull());
352159024ceSValeriy Savchenko const auto *APtrTy = dyn_cast<PointerType>(A.getType(Context));
353159024ceSValeriy Savchenko ASSERT_NE(APtrTy, nullptr);
354159024ceSValeriy Savchenko const auto *ARecordType = dyn_cast<RecordType>(APtrTy->getPointeeType());
355159024ceSValeriy Savchenko ASSERT_NE(ARecordType, nullptr);
356159024ceSValeriy Savchenko EXPECT_EQ("TestClass", ARecordType->getDecl()->getName());
357159024ceSValeriy Savchenko }
358159024ceSValeriy Savchenko
359159024ceSValeriy Savchenko SVAL_TEST(GetFunctionPtrType, R"(
360159024ceSValeriy Savchenko void bar();
361159024ceSValeriy Savchenko void foo() {
362159024ceSValeriy Savchenko auto *a = &bar;
363159024ceSValeriy Savchenko }
364159024ceSValeriy Savchenko )") {
365159024ceSValeriy Savchenko SVal A = getByName("a");
366159024ceSValeriy Savchenko ASSERT_FALSE(A.getType(Context).isNull());
367159024ceSValeriy Savchenko const auto *APtrTy = dyn_cast<PointerType>(A.getType(Context));
368159024ceSValeriy Savchenko ASSERT_NE(APtrTy, nullptr);
369159024ceSValeriy Savchenko ASSERT_TRUE(isa<FunctionProtoType>(APtrTy->getPointeeType()));
370159024ceSValeriy Savchenko }
371159024ceSValeriy Savchenko
372159024ceSValeriy Savchenko SVAL_TEST(GetLabelType, R"(
373159024ceSValeriy Savchenko void foo() {
374159024ceSValeriy Savchenko entry:
375159024ceSValeriy Savchenko void *a = &&entry;
376159024ceSValeriy Savchenko char *b = (char *)&&entry;
377159024ceSValeriy Savchenko }
378159024ceSValeriy Savchenko )") {
379159024ceSValeriy Savchenko SVal A = getByName("a");
380159024ceSValeriy Savchenko ASSERT_FALSE(A.getType(Context).isNull());
381159024ceSValeriy Savchenko EXPECT_EQ(Context.VoidPtrTy, A.getType(Context));
382159024ceSValeriy Savchenko
383159024ceSValeriy Savchenko SVal B = getByName("a");
384159024ceSValeriy Savchenko ASSERT_FALSE(B.getType(Context).isNull());
385159024ceSValeriy Savchenko // TODO: Change to CharTy when we support symbolic casts
386159024ceSValeriy Savchenko EXPECT_EQ(Context.VoidPtrTy, B.getType(Context));
387159024ceSValeriy Savchenko }
388159024ceSValeriy Savchenko
allTestClangConfigs()3899c4d194fSSteven Wan std::vector<TestClangConfig> allTestClangConfigs() {
3909c4d194fSSteven Wan std::vector<TestClangConfig> all_configs;
3919c4d194fSSteven Wan TestClangConfig config;
3929c4d194fSSteven Wan config.Language = Lang_CXX14;
3939c4d194fSSteven Wan for (std::string target :
3949c4d194fSSteven Wan {"i686-pc-windows-msvc", "i686-apple-darwin9",
3959c4d194fSSteven Wan "x86_64-apple-darwin9", "x86_64-scei-ps4",
3969c4d194fSSteven Wan "x86_64-windows-msvc", "x86_64-unknown-linux",
3979c4d194fSSteven Wan "x86_64-apple-macosx", "x86_64-apple-ios14.0",
3989c4d194fSSteven Wan "wasm32-unknown-unknown", "wasm64-unknown-unknown",
3999c4d194fSSteven Wan "thumb-pc-win32", "sparc64-none-openbsd",
4009c4d194fSSteven Wan "sparc-none-none", "riscv64-unknown-linux",
4019c4d194fSSteven Wan "ppc64-windows-msvc", "powerpc-ibm-aix",
4029c4d194fSSteven Wan "powerpc64-ibm-aix", "s390x-ibm-zos",
4039c4d194fSSteven Wan "armv7-pc-windows-msvc", "aarch64-pc-windows-msvc",
4049c4d194fSSteven Wan "xcore-xmos-elf"}) {
4059c4d194fSSteven Wan config.Target = target;
4069c4d194fSSteven Wan all_configs.push_back(config);
4079c4d194fSSteven Wan }
4089c4d194fSSteven Wan return all_configs;
4099c4d194fSSteven Wan }
4109c4d194fSSteven Wan
4119c4d194fSSteven Wan INSTANTIATE_TEST_SUITE_P(SValTests, SValTest,
4129c4d194fSSteven Wan testing::ValuesIn(allTestClangConfigs()));
4139c4d194fSSteven Wan
414159024ceSValeriy Savchenko } // namespace
415159024ceSValeriy Savchenko } // namespace ento
416159024ceSValeriy Savchenko } // namespace clang
417