xref: /llvm-project/clang/unittests/StaticAnalyzer/SValTest.cpp (revision 15f3cd6bfc670ba6106184a903eb04be059e5977)
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