1 | //===-- TestTypeSystemClang.cpp -------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "Plugins/ExpressionParser/Clang/ClangUtil.h" |
10 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
11 | #include "TestingSupport/SubsystemRAII.h" |
12 | #include "TestingSupport/Symbol/ClangTestUtils.h" |
13 | #include "lldb/Core/Declaration.h" |
14 | #include "lldb/Host/FileSystem.h" |
15 | #include "lldb/Host/HostInfo.h" |
16 | #include "clang/AST/DeclCXX.h" |
17 | #include "clang/AST/DeclObjC.h" |
18 | #include "clang/AST/ExprCXX.h" |
19 | #include "gtest/gtest.h" |
20 | |
21 | using namespace clang; |
22 | using namespace lldb; |
23 | using namespace lldb_private; |
24 | |
25 | class TestTypeSystemClang : public testing::Test { |
26 | public: |
27 | SubsystemRAII<FileSystem, HostInfo> subsystems; |
28 | |
29 | void SetUp() override { |
30 | m_holder = |
31 | std::make_unique<clang_utils::TypeSystemClangHolder>(args: "test ASTContext" ); |
32 | m_ast = m_holder->GetAST(); |
33 | } |
34 | |
35 | void TearDown() override { |
36 | m_ast = nullptr; |
37 | m_holder.reset(); |
38 | } |
39 | |
40 | protected: |
41 | |
42 | TypeSystemClang *m_ast = nullptr; |
43 | std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder; |
44 | |
45 | QualType GetBasicQualType(BasicType type) const { |
46 | return ClangUtil::GetQualType(ct: m_ast->GetBasicTypeFromAST(basic_type: type)); |
47 | } |
48 | |
49 | QualType GetBasicQualType(const char *name) const { |
50 | return ClangUtil::GetQualType( |
51 | ct: m_ast->GetBuiltinTypeByName(name: ConstString(name))); |
52 | } |
53 | }; |
54 | |
55 | TEST_F(TestTypeSystemClang, TestGetBasicTypeFromEnum) { |
56 | clang::ASTContext &context = m_ast->getASTContext(); |
57 | |
58 | EXPECT_TRUE( |
59 | context.hasSameType(GetBasicQualType(eBasicTypeBool), context.BoolTy)); |
60 | EXPECT_TRUE( |
61 | context.hasSameType(GetBasicQualType(eBasicTypeChar), context.CharTy)); |
62 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeChar8), |
63 | context.Char8Ty)); |
64 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeChar16), |
65 | context.Char16Ty)); |
66 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeChar32), |
67 | context.Char32Ty)); |
68 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeDouble), |
69 | context.DoubleTy)); |
70 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeDoubleComplex), |
71 | context.getComplexType(context.DoubleTy))); |
72 | EXPECT_TRUE( |
73 | context.hasSameType(GetBasicQualType(eBasicTypeFloat), context.FloatTy)); |
74 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeFloatComplex), |
75 | context.getComplexType(context.FloatTy))); |
76 | EXPECT_TRUE( |
77 | context.hasSameType(GetBasicQualType(eBasicTypeHalf), context.HalfTy)); |
78 | EXPECT_TRUE( |
79 | context.hasSameType(GetBasicQualType(eBasicTypeInt), context.IntTy)); |
80 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeInt128), |
81 | context.Int128Ty)); |
82 | EXPECT_TRUE( |
83 | context.hasSameType(GetBasicQualType(eBasicTypeLong), context.LongTy)); |
84 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeLongDouble), |
85 | context.LongDoubleTy)); |
86 | EXPECT_TRUE( |
87 | context.hasSameType(GetBasicQualType(eBasicTypeLongDoubleComplex), |
88 | context.getComplexType(context.LongDoubleTy))); |
89 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeLongLong), |
90 | context.LongLongTy)); |
91 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeNullPtr), |
92 | context.NullPtrTy)); |
93 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeObjCClass), |
94 | context.getObjCClassType())); |
95 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeObjCID), |
96 | context.getObjCIdType())); |
97 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeObjCSel), |
98 | context.getObjCSelType())); |
99 | EXPECT_TRUE( |
100 | context.hasSameType(GetBasicQualType(eBasicTypeShort), context.ShortTy)); |
101 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeSignedChar), |
102 | context.SignedCharTy)); |
103 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedChar), |
104 | context.UnsignedCharTy)); |
105 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedInt), |
106 | context.UnsignedIntTy)); |
107 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedInt128), |
108 | context.UnsignedInt128Ty)); |
109 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedLong), |
110 | context.UnsignedLongTy)); |
111 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedLongLong), |
112 | context.UnsignedLongLongTy)); |
113 | EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedShort), |
114 | context.UnsignedShortTy)); |
115 | EXPECT_TRUE( |
116 | context.hasSameType(GetBasicQualType(eBasicTypeVoid), context.VoidTy)); |
117 | EXPECT_TRUE( |
118 | context.hasSameType(GetBasicQualType(eBasicTypeWChar), context.WCharTy)); |
119 | } |
120 | |
121 | TEST_F(TestTypeSystemClang, TestGetBasicTypeFromName) { |
122 | EXPECT_EQ(GetBasicQualType(eBasicTypeChar), GetBasicQualType("char" )); |
123 | EXPECT_EQ(GetBasicQualType(eBasicTypeSignedChar), |
124 | GetBasicQualType("signed char" )); |
125 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedChar), |
126 | GetBasicQualType("unsigned char" )); |
127 | EXPECT_EQ(GetBasicQualType(eBasicTypeWChar), GetBasicQualType("wchar_t" )); |
128 | EXPECT_EQ(GetBasicQualType(eBasicTypeSignedWChar), |
129 | GetBasicQualType("signed wchar_t" )); |
130 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedWChar), |
131 | GetBasicQualType("unsigned wchar_t" )); |
132 | EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short" )); |
133 | EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short int" )); |
134 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort), |
135 | GetBasicQualType("unsigned short" )); |
136 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort), |
137 | GetBasicQualType("unsigned short int" )); |
138 | EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("int" )); |
139 | EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("signed int" )); |
140 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt), |
141 | GetBasicQualType("unsigned int" )); |
142 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt), |
143 | GetBasicQualType("unsigned" )); |
144 | EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long" )); |
145 | EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long int" )); |
146 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong), |
147 | GetBasicQualType("unsigned long" )); |
148 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong), |
149 | GetBasicQualType("unsigned long int" )); |
150 | EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong), |
151 | GetBasicQualType("long long" )); |
152 | EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong), |
153 | GetBasicQualType("long long int" )); |
154 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong), |
155 | GetBasicQualType("unsigned long long" )); |
156 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong), |
157 | GetBasicQualType("unsigned long long int" )); |
158 | EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128_t" )); |
159 | EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt128), |
160 | GetBasicQualType("__uint128_t" )); |
161 | EXPECT_EQ(GetBasicQualType(eBasicTypeVoid), GetBasicQualType("void" )); |
162 | EXPECT_EQ(GetBasicQualType(eBasicTypeBool), GetBasicQualType("bool" )); |
163 | EXPECT_EQ(GetBasicQualType(eBasicTypeFloat), GetBasicQualType("float" )); |
164 | EXPECT_EQ(GetBasicQualType(eBasicTypeDouble), GetBasicQualType("double" )); |
165 | EXPECT_EQ(GetBasicQualType(eBasicTypeLongDouble), |
166 | GetBasicQualType("long double" )); |
167 | EXPECT_EQ(GetBasicQualType(eBasicTypeObjCID), GetBasicQualType("id" )); |
168 | EXPECT_EQ(GetBasicQualType(eBasicTypeObjCSel), GetBasicQualType("SEL" )); |
169 | EXPECT_EQ(GetBasicQualType(eBasicTypeNullPtr), GetBasicQualType("nullptr" )); |
170 | } |
171 | |
172 | void VerifyEncodingAndBitSize(TypeSystemClang &clang_context, |
173 | lldb::Encoding encoding, unsigned int bit_size) { |
174 | clang::ASTContext &context = clang_context.getASTContext(); |
175 | |
176 | CompilerType type = |
177 | clang_context.GetBuiltinTypeForEncodingAndBitSize(encoding, bit_size); |
178 | EXPECT_TRUE(type.IsValid()); |
179 | |
180 | QualType qtype = ClangUtil::GetQualType(ct: type); |
181 | EXPECT_FALSE(qtype.isNull()); |
182 | if (qtype.isNull()) |
183 | return; |
184 | |
185 | uint64_t actual_size = context.getTypeSize(T: qtype); |
186 | EXPECT_EQ(bit_size, actual_size); |
187 | |
188 | const clang::Type *type_ptr = qtype.getTypePtr(); |
189 | EXPECT_NE(nullptr, type_ptr); |
190 | if (!type_ptr) |
191 | return; |
192 | |
193 | EXPECT_TRUE(type_ptr->isBuiltinType()); |
194 | switch (encoding) { |
195 | case eEncodingSint: |
196 | EXPECT_TRUE(type_ptr->isSignedIntegerType()); |
197 | break; |
198 | case eEncodingUint: |
199 | EXPECT_TRUE(type_ptr->isUnsignedIntegerType()); |
200 | break; |
201 | case eEncodingIEEE754: |
202 | EXPECT_TRUE(type_ptr->isFloatingType()); |
203 | break; |
204 | default: |
205 | FAIL() << "Unexpected encoding" ; |
206 | break; |
207 | } |
208 | } |
209 | |
210 | TEST_F(TestTypeSystemClang, TestBuiltinTypeForEncodingAndBitSize) { |
211 | // Make sure we can get types of every possible size in every possible |
212 | // encoding. |
213 | // We can't make any guarantee about which specific type we get, because the |
214 | // standard |
215 | // isn't that specific. We only need to make sure the compiler hands us some |
216 | // type that |
217 | // is both a builtin type and matches the requested bit size. |
218 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingSint, bit_size: 8); |
219 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingSint, bit_size: 16); |
220 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingSint, bit_size: 32); |
221 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingSint, bit_size: 64); |
222 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingSint, bit_size: 128); |
223 | |
224 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingUint, bit_size: 8); |
225 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingUint, bit_size: 16); |
226 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingUint, bit_size: 32); |
227 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingUint, bit_size: 64); |
228 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingUint, bit_size: 128); |
229 | |
230 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingIEEE754, bit_size: 32); |
231 | VerifyEncodingAndBitSize(clang_context&: *m_ast, encoding: eEncodingIEEE754, bit_size: 64); |
232 | } |
233 | |
234 | TEST_F(TestTypeSystemClang, TestDisplayName) { |
235 | TypeSystemClang ast("some name" , llvm::Triple()); |
236 | EXPECT_EQ("some name" , ast.getDisplayName()); |
237 | } |
238 | |
239 | TEST_F(TestTypeSystemClang, TestDisplayNameEmpty) { |
240 | TypeSystemClang ast("" , llvm::Triple()); |
241 | EXPECT_EQ("" , ast.getDisplayName()); |
242 | } |
243 | |
244 | TEST_F(TestTypeSystemClang, TestGetEnumIntegerTypeInvalid) { |
245 | EXPECT_FALSE(m_ast->GetEnumerationIntegerType(CompilerType()).IsValid()); |
246 | } |
247 | |
248 | TEST_F(TestTypeSystemClang, TestGetEnumIntegerTypeUnexpectedType) { |
249 | CompilerType int_type = m_ast->GetBasicType(type: lldb::eBasicTypeInt); |
250 | CompilerType t = m_ast->GetEnumerationIntegerType(type: int_type); |
251 | EXPECT_FALSE(t.IsValid()); |
252 | } |
253 | |
254 | TEST_F(TestTypeSystemClang, TestGetEnumIntegerTypeBasicTypes) { |
255 | // All possible underlying integer types of enums. |
256 | const std::vector<lldb::BasicType> types_to_test = { |
257 | eBasicTypeInt, eBasicTypeUnsignedInt, eBasicTypeLong, |
258 | eBasicTypeUnsignedLong, eBasicTypeLongLong, eBasicTypeUnsignedLongLong, |
259 | }; |
260 | |
261 | for (bool scoped : {true, false}) { |
262 | SCOPED_TRACE("scoped: " + std::to_string(scoped)); |
263 | for (lldb::BasicType basic_type : types_to_test) { |
264 | SCOPED_TRACE(std::to_string(basic_type)); |
265 | |
266 | auto holder = |
267 | std::make_unique<clang_utils::TypeSystemClangHolder>(args: "enum_ast" ); |
268 | auto &ast = *holder->GetAST(); |
269 | |
270 | CompilerType basic_compiler_type = ast.GetBasicType(type: basic_type); |
271 | EXPECT_TRUE(basic_compiler_type.IsValid()); |
272 | |
273 | CompilerType enum_type = ast.CreateEnumerationType( |
274 | "my_enum" , ast.GetTranslationUnitDecl(), OptionalClangModuleID(), |
275 | Declaration(), basic_compiler_type, scoped); |
276 | |
277 | CompilerType t = ast.GetEnumerationIntegerType(type: enum_type); |
278 | // Check that the type we put in at the start is found again. |
279 | EXPECT_EQ(basic_compiler_type.GetTypeName(), t.GetTypeName()); |
280 | } |
281 | } |
282 | } |
283 | |
284 | TEST_F(TestTypeSystemClang, TestOwningModule) { |
285 | auto holder = |
286 | std::make_unique<clang_utils::TypeSystemClangHolder>(args: "module_ast" ); |
287 | auto &ast = *holder->GetAST(); |
288 | CompilerType basic_compiler_type = ast.GetBasicType(type: BasicType::eBasicTypeInt); |
289 | CompilerType enum_type = ast.CreateEnumerationType( |
290 | "my_enum" , ast.GetTranslationUnitDecl(), OptionalClangModuleID(100), |
291 | Declaration(), basic_compiler_type, false); |
292 | auto *ed = TypeSystemClang::GetAsEnumDecl(type: enum_type); |
293 | EXPECT_FALSE(!ed); |
294 | EXPECT_EQ(ed->getOwningModuleID(), 100u); |
295 | |
296 | CompilerType record_type = ast.CreateRecordType( |
297 | decl_ctx: nullptr, owning_module: OptionalClangModuleID(200), access_type: lldb::eAccessPublic, name: "FooRecord" , |
298 | kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), |
299 | language: lldb::eLanguageTypeC_plus_plus, metadata: nullptr); |
300 | auto *rd = TypeSystemClang::GetAsRecordDecl(type: record_type); |
301 | EXPECT_FALSE(!rd); |
302 | EXPECT_EQ(rd->getOwningModuleID(), 200u); |
303 | |
304 | CompilerType class_type = |
305 | ast.CreateObjCClass("objc_class" , ast.GetTranslationUnitDecl(), |
306 | OptionalClangModuleID(300), false, false); |
307 | auto *cd = TypeSystemClang::GetAsObjCInterfaceDecl(type: class_type); |
308 | EXPECT_FALSE(!cd); |
309 | EXPECT_EQ(cd->getOwningModuleID(), 300u); |
310 | } |
311 | |
312 | TEST_F(TestTypeSystemClang, TestIsClangType) { |
313 | clang::ASTContext &context = m_ast->getASTContext(); |
314 | lldb::opaque_compiler_type_t bool_ctype = |
315 | TypeSystemClang::GetOpaqueCompilerType(ast: &context, basic_type: lldb::eBasicTypeBool); |
316 | CompilerType bool_type(m_ast->weak_from_this(), bool_ctype); |
317 | CompilerType record_type = m_ast->CreateRecordType( |
318 | decl_ctx: nullptr, owning_module: OptionalClangModuleID(100), access_type: lldb::eAccessPublic, name: "FooRecord" , |
319 | kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), |
320 | language: lldb::eLanguageTypeC_plus_plus, metadata: nullptr); |
321 | // Clang builtin type and record type should pass |
322 | EXPECT_TRUE(ClangUtil::IsClangType(bool_type)); |
323 | EXPECT_TRUE(ClangUtil::IsClangType(record_type)); |
324 | |
325 | // Default constructed type should fail |
326 | EXPECT_FALSE(ClangUtil::IsClangType(CompilerType())); |
327 | } |
328 | |
329 | TEST_F(TestTypeSystemClang, TestRemoveFastQualifiers) { |
330 | CompilerType record_type = m_ast->CreateRecordType( |
331 | decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, name: "FooRecord" , |
332 | kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), |
333 | language: lldb::eLanguageTypeC_plus_plus, metadata: nullptr); |
334 | QualType qt; |
335 | |
336 | qt = ClangUtil::GetQualType(ct: record_type); |
337 | EXPECT_EQ(0u, qt.getLocalFastQualifiers()); |
338 | record_type = record_type.AddConstModifier(); |
339 | record_type = record_type.AddVolatileModifier(); |
340 | record_type = record_type.AddRestrictModifier(); |
341 | qt = ClangUtil::GetQualType(ct: record_type); |
342 | EXPECT_NE(0u, qt.getLocalFastQualifiers()); |
343 | record_type = ClangUtil::RemoveFastQualifiers(ct: record_type); |
344 | qt = ClangUtil::GetQualType(ct: record_type); |
345 | EXPECT_EQ(0u, qt.getLocalFastQualifiers()); |
346 | } |
347 | |
348 | TEST_F(TestTypeSystemClang, TestConvertAccessTypeToAccessSpecifier) { |
349 | EXPECT_EQ(AS_none, |
350 | TypeSystemClang::ConvertAccessTypeToAccessSpecifier(eAccessNone)); |
351 | EXPECT_EQ(AS_none, TypeSystemClang::ConvertAccessTypeToAccessSpecifier( |
352 | eAccessPackage)); |
353 | EXPECT_EQ(AS_public, |
354 | TypeSystemClang::ConvertAccessTypeToAccessSpecifier(eAccessPublic)); |
355 | EXPECT_EQ(AS_private, TypeSystemClang::ConvertAccessTypeToAccessSpecifier( |
356 | eAccessPrivate)); |
357 | EXPECT_EQ(AS_protected, TypeSystemClang::ConvertAccessTypeToAccessSpecifier( |
358 | eAccessProtected)); |
359 | } |
360 | |
361 | TEST_F(TestTypeSystemClang, TestUnifyAccessSpecifiers) { |
362 | // Unifying two of the same type should return the same type |
363 | EXPECT_EQ(AS_public, |
364 | TypeSystemClang::UnifyAccessSpecifiers(AS_public, AS_public)); |
365 | EXPECT_EQ(AS_private, |
366 | TypeSystemClang::UnifyAccessSpecifiers(AS_private, AS_private)); |
367 | EXPECT_EQ(AS_protected, |
368 | TypeSystemClang::UnifyAccessSpecifiers(AS_protected, AS_protected)); |
369 | |
370 | // Otherwise the result should be the strictest of the two. |
371 | EXPECT_EQ(AS_private, |
372 | TypeSystemClang::UnifyAccessSpecifiers(AS_private, AS_public)); |
373 | EXPECT_EQ(AS_private, |
374 | TypeSystemClang::UnifyAccessSpecifiers(AS_private, AS_protected)); |
375 | EXPECT_EQ(AS_private, |
376 | TypeSystemClang::UnifyAccessSpecifiers(AS_public, AS_private)); |
377 | EXPECT_EQ(AS_private, |
378 | TypeSystemClang::UnifyAccessSpecifiers(AS_protected, AS_private)); |
379 | EXPECT_EQ(AS_protected, |
380 | TypeSystemClang::UnifyAccessSpecifiers(AS_protected, AS_public)); |
381 | EXPECT_EQ(AS_protected, |
382 | TypeSystemClang::UnifyAccessSpecifiers(AS_public, AS_protected)); |
383 | |
384 | // None is stricter than everything (by convention) |
385 | EXPECT_EQ(AS_none, |
386 | TypeSystemClang::UnifyAccessSpecifiers(AS_none, AS_public)); |
387 | EXPECT_EQ(AS_none, |
388 | TypeSystemClang::UnifyAccessSpecifiers(AS_none, AS_protected)); |
389 | EXPECT_EQ(AS_none, |
390 | TypeSystemClang::UnifyAccessSpecifiers(AS_none, AS_private)); |
391 | EXPECT_EQ(AS_none, |
392 | TypeSystemClang::UnifyAccessSpecifiers(AS_public, AS_none)); |
393 | EXPECT_EQ(AS_none, |
394 | TypeSystemClang::UnifyAccessSpecifiers(AS_protected, AS_none)); |
395 | EXPECT_EQ(AS_none, |
396 | TypeSystemClang::UnifyAccessSpecifiers(AS_private, AS_none)); |
397 | } |
398 | |
399 | TEST_F(TestTypeSystemClang, TestRecordHasFields) { |
400 | CompilerType int_type = m_ast->GetBasicType(type: eBasicTypeInt); |
401 | |
402 | // Test that a record with no fields returns false |
403 | CompilerType empty_base = m_ast->CreateRecordType( |
404 | decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, name: "EmptyBase" , |
405 | kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), |
406 | language: lldb::eLanguageTypeC_plus_plus, metadata: nullptr); |
407 | TypeSystemClang::StartTagDeclarationDefinition(type: empty_base); |
408 | TypeSystemClang::CompleteTagDeclarationDefinition(type: empty_base); |
409 | |
410 | RecordDecl *empty_base_decl = TypeSystemClang::GetAsRecordDecl(type: empty_base); |
411 | EXPECT_NE(nullptr, empty_base_decl); |
412 | EXPECT_FALSE(m_ast->RecordHasFields(empty_base_decl)); |
413 | |
414 | // Test that a record with direct fields returns true |
415 | CompilerType non_empty_base = m_ast->CreateRecordType( |
416 | decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, name: "NonEmptyBase" , |
417 | kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), |
418 | language: lldb::eLanguageTypeC_plus_plus, metadata: nullptr); |
419 | TypeSystemClang::StartTagDeclarationDefinition(type: non_empty_base); |
420 | FieldDecl *non_empty_base_field_decl = m_ast->AddFieldToRecordType( |
421 | type: non_empty_base, name: "MyField" , field_type: int_type, access: eAccessPublic, bitfield_bit_size: 0); |
422 | TypeSystemClang::CompleteTagDeclarationDefinition(type: non_empty_base); |
423 | RecordDecl *non_empty_base_decl = |
424 | TypeSystemClang::GetAsRecordDecl(type: non_empty_base); |
425 | EXPECT_NE(nullptr, non_empty_base_decl); |
426 | EXPECT_NE(nullptr, non_empty_base_field_decl); |
427 | EXPECT_TRUE(m_ast->RecordHasFields(non_empty_base_decl)); |
428 | |
429 | std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; |
430 | |
431 | // Test that a record with no direct fields, but fields in a base returns true |
432 | CompilerType empty_derived = m_ast->CreateRecordType( |
433 | decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, name: "EmptyDerived" , |
434 | kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), |
435 | language: lldb::eLanguageTypeC_plus_plus, metadata: nullptr); |
436 | TypeSystemClang::StartTagDeclarationDefinition(type: empty_derived); |
437 | std::unique_ptr<clang::CXXBaseSpecifier> non_empty_base_spec = |
438 | m_ast->CreateBaseClassSpecifier(type: non_empty_base.GetOpaqueQualType(), |
439 | access: lldb::eAccessPublic, is_virtual: false, base_of_class: false); |
440 | bases.push_back(x: std::move(non_empty_base_spec)); |
441 | bool result = m_ast->TransferBaseClasses(type: empty_derived.GetOpaqueQualType(), |
442 | bases: std::move(bases)); |
443 | TypeSystemClang::CompleteTagDeclarationDefinition(type: empty_derived); |
444 | EXPECT_TRUE(result); |
445 | CXXRecordDecl *empty_derived_non_empty_base_cxx_decl = |
446 | m_ast->GetAsCXXRecordDecl(type: empty_derived.GetOpaqueQualType()); |
447 | RecordDecl *empty_derived_non_empty_base_decl = |
448 | TypeSystemClang::GetAsRecordDecl(type: empty_derived); |
449 | EXPECT_EQ(1u, m_ast->GetNumBaseClasses( |
450 | empty_derived_non_empty_base_cxx_decl, false)); |
451 | EXPECT_TRUE(m_ast->RecordHasFields(empty_derived_non_empty_base_decl)); |
452 | |
453 | // Test that a record with no direct fields, but fields in a virtual base |
454 | // returns true |
455 | CompilerType empty_derived2 = m_ast->CreateRecordType( |
456 | decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, name: "EmptyDerived2" , |
457 | kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), |
458 | language: lldb::eLanguageTypeC_plus_plus, metadata: nullptr); |
459 | TypeSystemClang::StartTagDeclarationDefinition(type: empty_derived2); |
460 | std::unique_ptr<CXXBaseSpecifier> non_empty_vbase_spec = |
461 | m_ast->CreateBaseClassSpecifier(type: non_empty_base.GetOpaqueQualType(), |
462 | access: lldb::eAccessPublic, is_virtual: true, base_of_class: false); |
463 | bases.push_back(x: std::move(non_empty_vbase_spec)); |
464 | result = m_ast->TransferBaseClasses(type: empty_derived2.GetOpaqueQualType(), |
465 | bases: std::move(bases)); |
466 | TypeSystemClang::CompleteTagDeclarationDefinition(type: empty_derived2); |
467 | EXPECT_TRUE(result); |
468 | CXXRecordDecl *empty_derived_non_empty_vbase_cxx_decl = |
469 | m_ast->GetAsCXXRecordDecl(type: empty_derived2.GetOpaqueQualType()); |
470 | RecordDecl *empty_derived_non_empty_vbase_decl = |
471 | TypeSystemClang::GetAsRecordDecl(type: empty_derived2); |
472 | EXPECT_EQ(1u, m_ast->GetNumBaseClasses( |
473 | empty_derived_non_empty_vbase_cxx_decl, false)); |
474 | EXPECT_TRUE( |
475 | m_ast->RecordHasFields(empty_derived_non_empty_vbase_decl)); |
476 | } |
477 | |
478 | TEST_F(TestTypeSystemClang, TemplateArguments) { |
479 | TypeSystemClang::TemplateParameterInfos infos; |
480 | infos.InsertArg(name: "T" , arg: TemplateArgument(m_ast->getASTContext().IntTy)); |
481 | |
482 | llvm::APSInt arg(llvm::APInt(8, 47)); |
483 | infos.InsertArg(name: "I" , arg: TemplateArgument(m_ast->getASTContext(), arg, |
484 | m_ast->getASTContext().IntTy)); |
485 | |
486 | // template<typename T, int I> struct foo; |
487 | ClassTemplateDecl *decl = m_ast->CreateClassTemplateDecl( |
488 | m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), eAccessPublic, |
489 | "foo" , llvm::to_underlying(E: clang::TagTypeKind::Struct), infos); |
490 | ASSERT_NE(decl, nullptr); |
491 | |
492 | // foo<int, 47> |
493 | ClassTemplateSpecializationDecl *spec_decl = |
494 | m_ast->CreateClassTemplateSpecializationDecl( |
495 | m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), decl, |
496 | llvm::to_underlying(E: clang::TagTypeKind::Struct), infos); |
497 | ASSERT_NE(spec_decl, nullptr); |
498 | CompilerType type = m_ast->CreateClassTemplateSpecializationType(spec_decl); |
499 | ASSERT_TRUE(type); |
500 | m_ast->StartTagDeclarationDefinition(type); |
501 | m_ast->CompleteTagDeclarationDefinition(type); |
502 | |
503 | // typedef foo<int, 47> foo_def; |
504 | CompilerType typedef_type = type.CreateTypedef( |
505 | name: "foo_def" , decl_ctx: m_ast->CreateDeclContext(m_ast->GetTranslationUnitDecl()), payload: 0); |
506 | |
507 | CompilerType auto_type( |
508 | m_ast->weak_from_this(), |
509 | m_ast->getASTContext() |
510 | .getAutoType(DeducedType: ClangUtil::GetCanonicalQualType(ct: typedef_type), |
511 | Keyword: clang::AutoTypeKeyword::Auto, IsDependent: false) |
512 | .getAsOpaquePtr()); |
513 | |
514 | CompilerType int_type(m_ast->weak_from_this(), |
515 | m_ast->getASTContext().IntTy.getAsOpaquePtr()); |
516 | for (CompilerType t : {type, typedef_type, auto_type}) { |
517 | SCOPED_TRACE(t.GetTypeName().AsCString()); |
518 | |
519 | const bool expand_pack = false; |
520 | EXPECT_EQ( |
521 | m_ast->GetTemplateArgumentKind(t.GetOpaqueQualType(), 0, expand_pack), |
522 | eTemplateArgumentKindType); |
523 | EXPECT_EQ( |
524 | m_ast->GetTypeTemplateArgument(t.GetOpaqueQualType(), 0, expand_pack), |
525 | int_type); |
526 | EXPECT_EQ(std::nullopt, m_ast->GetIntegralTemplateArgument( |
527 | t.GetOpaqueQualType(), 0, expand_pack)); |
528 | |
529 | EXPECT_EQ( |
530 | m_ast->GetTemplateArgumentKind(t.GetOpaqueQualType(), 1, expand_pack), |
531 | eTemplateArgumentKindIntegral); |
532 | EXPECT_EQ( |
533 | m_ast->GetTypeTemplateArgument(t.GetOpaqueQualType(), 1, expand_pack), |
534 | CompilerType()); |
535 | auto result = m_ast->GetIntegralTemplateArgument(t.GetOpaqueQualType(), 1, |
536 | expand_pack); |
537 | ASSERT_NE(std::nullopt, result); |
538 | EXPECT_EQ(arg, result->value); |
539 | EXPECT_EQ(int_type, result->type); |
540 | } |
541 | } |
542 | |
543 | class TestCreateClassTemplateDecl : public TestTypeSystemClang { |
544 | protected: |
545 | /// The class templates created so far by the Expect* functions below. |
546 | llvm::DenseSet<ClassTemplateDecl *> m_created_templates; |
547 | |
548 | /// Utility function for creating a class template. |
549 | ClassTemplateDecl * |
550 | CreateClassTemplate(const TypeSystemClang::TemplateParameterInfos &infos) { |
551 | ClassTemplateDecl *decl = m_ast->CreateClassTemplateDecl( |
552 | m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), eAccessPublic, |
553 | "foo" , llvm::to_underlying(E: clang::TagTypeKind::Struct), infos); |
554 | return decl; |
555 | } |
556 | |
557 | /// Creates a new class template with the given template parameters. |
558 | /// Asserts that a new ClassTemplateDecl is created. |
559 | /// \param description The gtest scope string that should describe the input. |
560 | /// \param infos The template parameters that the class template should have. |
561 | /// \returns The created ClassTemplateDecl. |
562 | ClassTemplateDecl * |
563 | ExpectNewTemplate(std::string description, |
564 | const TypeSystemClang::TemplateParameterInfos &infos) { |
565 | SCOPED_TRACE(description); |
566 | ClassTemplateDecl *first_template = CreateClassTemplate(infos); |
567 | // A new template should have been created. |
568 | EXPECT_FALSE(m_created_templates.contains(first_template)) |
569 | << "Didn't create new class template but reused this existing decl:\n" |
570 | << ClangUtil::DumpDecl(first_template); |
571 | m_created_templates.insert(V: first_template); |
572 | |
573 | // Creating a new template with the same arguments should always return |
574 | // the template created above. |
575 | ClassTemplateDecl *second_template = CreateClassTemplate(infos); |
576 | EXPECT_EQ(first_template, second_template) |
577 | << "Second attempt to create class template didn't reuse first decl:\n" |
578 | << ClangUtil::DumpDecl(first_template) << "\nInstead created/reused:\n" |
579 | << ClangUtil::DumpDecl(second_template); |
580 | return first_template; |
581 | } |
582 | |
583 | /// Tries to create a new class template but asserts that an existing class |
584 | /// template in the current AST is reused (in contract so a new class |
585 | /// template being created). |
586 | /// \param description The gtest scope string that should describe the input. |
587 | /// \param infos The template parameters that the class template should have. |
588 | void |
589 | ExpectReusedTemplate(std::string description, |
590 | const TypeSystemClang::TemplateParameterInfos &infos, |
591 | ClassTemplateDecl *expected) { |
592 | SCOPED_TRACE(description); |
593 | ClassTemplateDecl *td = CreateClassTemplate(infos); |
594 | EXPECT_EQ(td, expected) |
595 | << "Created/reused class template is:\n" |
596 | << ClangUtil::DumpDecl(td) << "\nExpected to reuse:\n" |
597 | << ClangUtil::DumpDecl(expected); |
598 | } |
599 | }; |
600 | |
601 | TEST_F(TestCreateClassTemplateDecl, FindExistingTemplates) { |
602 | // This tests the logic in TypeSystemClang::CreateClassTemplateDecl that |
603 | // decides whether an existing ClassTemplateDecl in the AST can be reused. |
604 | // The behaviour should follow the C++ rules for redeclaring templates |
605 | // (e.g., parameter names can be changed/omitted.) |
606 | |
607 | // Test an empty template parameter list: <> |
608 | ExpectNewTemplate(description: "<>" , infos: {{}, {}}); |
609 | |
610 | clang::TemplateArgument intArg(m_ast->getASTContext().IntTy); |
611 | clang::TemplateArgument int47Arg(m_ast->getASTContext(), |
612 | llvm::APSInt(llvm::APInt(32, 47)), |
613 | m_ast->getASTContext().IntTy); |
614 | clang::TemplateArgument floatArg(m_ast->getASTContext().FloatTy); |
615 | clang::TemplateArgument char47Arg(m_ast->getASTContext(), |
616 | llvm::APSInt(llvm::APInt(8, 47)), |
617 | m_ast->getASTContext().SignedCharTy); |
618 | |
619 | clang::TemplateArgument char123Arg(m_ast->getASTContext(), |
620 | llvm::APSInt(llvm::APInt(8, 123)), |
621 | m_ast->getASTContext().SignedCharTy); |
622 | |
623 | // Test that <typename T> with T = int creates a new template. |
624 | ClassTemplateDecl *single_type_arg = |
625 | ExpectNewTemplate(description: "<typename T>" , infos: {{"T" }, {intArg}}); |
626 | |
627 | // Test that changing the parameter name doesn't create a new class template. |
628 | ExpectReusedTemplate(description: "<typename A> (A = int)" , infos: {{"A" }, {intArg}}, |
629 | expected: single_type_arg); |
630 | |
631 | // Test that changing the used type doesn't create a new class template. |
632 | ExpectReusedTemplate(description: "<typename A> (A = float)" , infos: {{"A" }, {floatArg}}, |
633 | expected: single_type_arg); |
634 | |
635 | // Test that <typename A, signed char I> creates a new template with A = int |
636 | // and I = 47; |
637 | ClassTemplateDecl *type_and_char_value = |
638 | ExpectNewTemplate(description: "<typename A, signed char I> (I = 47)" , |
639 | infos: {{"A" , "I" }, {floatArg, char47Arg}}); |
640 | |
641 | // Change the value of the I parameter to 123. The previously created |
642 | // class template should still be reused. |
643 | ExpectReusedTemplate(description: "<typename A, signed char I> (I = 123)" , |
644 | infos: {{"A" , "I" }, {floatArg, char123Arg}}, |
645 | expected: type_and_char_value); |
646 | |
647 | // Change the type of the I parameter to int so we have <typename A, int I>. |
648 | // The class template from above can't be reused. |
649 | ExpectNewTemplate(description: "<typename A, int I> (I = 123)" , |
650 | infos: {{"A" , "I" }, {floatArg, int47Arg}}); |
651 | |
652 | // Test a second type parameter will also cause a new template to be created. |
653 | // We now have <typename A, int I, typename B>. |
654 | ClassTemplateDecl *type_and_char_value_and_type = |
655 | ExpectNewTemplate(description: "<typename A, int I, typename B>" , |
656 | infos: {{"A" , "I" , "B" }, {floatArg, int47Arg, intArg}}); |
657 | |
658 | // Remove all the names from the parameters which shouldn't influence the |
659 | // way the templates get merged. |
660 | ExpectReusedTemplate(description: "<typename, int, typename>" , |
661 | infos: {{"" , "" , "" }, {floatArg, int47Arg, intArg}}, |
662 | expected: type_and_char_value_and_type); |
663 | } |
664 | |
665 | TEST_F(TestCreateClassTemplateDecl, FindExistingTemplatesWithParameterPack) { |
666 | // The same as FindExistingTemplates but for templates with parameter packs. |
667 | TypeSystemClang::TemplateParameterInfos infos; |
668 | clang::TemplateArgument intArg(m_ast->getASTContext().IntTy); |
669 | clang::TemplateArgument int1Arg(m_ast->getASTContext(), |
670 | llvm::APSInt(llvm::APInt(32, 1)), |
671 | m_ast->getASTContext().IntTy); |
672 | clang::TemplateArgument int123Arg(m_ast->getASTContext(), |
673 | llvm::APSInt(llvm::APInt(32, 123)), |
674 | m_ast->getASTContext().IntTy); |
675 | clang::TemplateArgument longArg(m_ast->getASTContext().LongTy); |
676 | clang::TemplateArgument long1Arg(m_ast->getASTContext(), |
677 | llvm::APSInt(llvm::APInt(64, 1)), |
678 | m_ast->getASTContext().LongTy); |
679 | |
680 | infos.SetParameterPack( |
681 | std::make_unique<TypeSystemClang::TemplateParameterInfos>( |
682 | args: llvm::SmallVector<const char *>{"" , "" }, |
683 | args: llvm::SmallVector<TemplateArgument>{intArg, intArg})); |
684 | |
685 | ClassTemplateDecl *type_pack = |
686 | ExpectNewTemplate(description: "<typename ...> (int, int)" , infos); |
687 | |
688 | // Special case: An instantiation for a parameter pack with no values fits |
689 | // to whatever class template we find. There isn't enough information to |
690 | // do an actual comparison here. |
691 | infos.SetParameterPack( |
692 | std::make_unique<TypeSystemClang::TemplateParameterInfos>()); |
693 | ExpectReusedTemplate(description: "<...> (no values in pack)" , infos, expected: type_pack); |
694 | |
695 | // Change the type content of pack type values. |
696 | infos.SetParameterPack( |
697 | std::make_unique<TypeSystemClang::TemplateParameterInfos>( |
698 | args: llvm::SmallVector<const char *>{"" , "" }, |
699 | args: llvm::SmallVector<TemplateArgument>{intArg, longArg})); |
700 | ExpectReusedTemplate(description: "<typename ...> (int, long)" , infos, expected: type_pack); |
701 | |
702 | // Change the number of pack values. |
703 | infos.SetParameterPack( |
704 | std::make_unique<TypeSystemClang::TemplateParameterInfos>( |
705 | args: llvm::SmallVector<const char *>{"" }, |
706 | args: llvm::SmallVector<TemplateArgument>{intArg})); |
707 | ExpectReusedTemplate(description: "<typename ...> (int)" , infos, expected: type_pack); |
708 | |
709 | // The names of the pack values shouldn't matter. |
710 | infos.SetParameterPack( |
711 | std::make_unique<TypeSystemClang::TemplateParameterInfos>( |
712 | args: llvm::SmallVector<const char *>{"A" }, |
713 | args: llvm::SmallVector<TemplateArgument>{intArg})); |
714 | ExpectReusedTemplate(description: "<typename ...> (int)" , infos, expected: type_pack); |
715 | |
716 | // Changing the kind of template argument will create a new template. |
717 | infos.SetParameterPack( |
718 | std::make_unique<TypeSystemClang::TemplateParameterInfos>( |
719 | args: llvm::SmallVector<const char *>{"A" }, |
720 | args: llvm::SmallVector<TemplateArgument>{int1Arg})); |
721 | ClassTemplateDecl *int_pack = ExpectNewTemplate(description: "<int ...> (int = 1)" , infos); |
722 | |
723 | // Changing the value of integral parameters will not create a new template. |
724 | infos.SetParameterPack( |
725 | std::make_unique<TypeSystemClang::TemplateParameterInfos>( |
726 | args: llvm::SmallVector<const char *>{"A" }, |
727 | args: llvm::SmallVector<TemplateArgument>{int123Arg})); |
728 | ExpectReusedTemplate(description: "<int ...> (int = 123)" , infos, expected: int_pack); |
729 | |
730 | // Changing the integral type will create a new template. |
731 | infos.SetParameterPack( |
732 | std::make_unique<TypeSystemClang::TemplateParameterInfos>( |
733 | args: llvm::SmallVector<const char *>{"A" }, |
734 | args: llvm::SmallVector<TemplateArgument>{long1Arg})); |
735 | ExpectNewTemplate(description: "<long ...> (long = 1)" , infos); |
736 | |
737 | // Prependinding a non-pack parameter will create a new template. |
738 | infos.InsertArg(name: "T" , arg: intArg); |
739 | ExpectNewTemplate(description: "<typename T, long...> (T = int, long = 1)" , infos); |
740 | } |
741 | |
742 | TEST_F(TestTypeSystemClang, OnlyPackName) { |
743 | TypeSystemClang::TemplateParameterInfos infos; |
744 | infos.SetPackName("A" ); |
745 | EXPECT_FALSE(infos.IsValid()); |
746 | } |
747 | |
748 | static QualType makeConstInt(clang::ASTContext &ctxt) { |
749 | QualType result(ctxt.IntTy); |
750 | result.addConst(); |
751 | return result; |
752 | } |
753 | |
754 | TEST_F(TestTypeSystemClang, TestGetTypeClassDeclType) { |
755 | clang::ASTContext &ctxt = m_ast->getASTContext(); |
756 | auto *nullptr_expr = new (ctxt) CXXNullPtrLiteralExpr(ctxt.NullPtrTy, SourceLocation()); |
757 | QualType t = ctxt.getDecltypeType(e: nullptr_expr, UnderlyingType: makeConstInt(ctxt)); |
758 | EXPECT_EQ(lldb::eTypeClassBuiltin, m_ast->GetTypeClass(t.getAsOpaquePtr())); |
759 | } |
760 | |
761 | TEST_F(TestTypeSystemClang, TestGetTypeClassTypeOf) { |
762 | clang::ASTContext &ctxt = m_ast->getASTContext(); |
763 | QualType t = ctxt.getTypeOfType(QT: makeConstInt(ctxt), Kind: TypeOfKind::Qualified); |
764 | EXPECT_EQ(lldb::eTypeClassBuiltin, m_ast->GetTypeClass(t.getAsOpaquePtr())); |
765 | } |
766 | |
767 | TEST_F(TestTypeSystemClang, TestGetTypeClassTypeOfExpr) { |
768 | clang::ASTContext &ctxt = m_ast->getASTContext(); |
769 | auto *nullptr_expr = new (ctxt) CXXNullPtrLiteralExpr(ctxt.NullPtrTy, SourceLocation()); |
770 | QualType t = ctxt.getTypeOfExprType(E: nullptr_expr, Kind: TypeOfKind::Qualified); |
771 | EXPECT_EQ(lldb::eTypeClassBuiltin, m_ast->GetTypeClass(t.getAsOpaquePtr())); |
772 | } |
773 | |
774 | TEST_F(TestTypeSystemClang, TestGetTypeClassNested) { |
775 | clang::ASTContext &ctxt = m_ast->getASTContext(); |
776 | QualType t_base = |
777 | ctxt.getTypeOfType(QT: makeConstInt(ctxt), Kind: TypeOfKind::Qualified); |
778 | QualType t = ctxt.getTypeOfType(QT: t_base, Kind: TypeOfKind::Qualified); |
779 | EXPECT_EQ(lldb::eTypeClassBuiltin, m_ast->GetTypeClass(t.getAsOpaquePtr())); |
780 | } |
781 | |
782 | TEST_F(TestTypeSystemClang, TestFunctionTemplateConstruction) { |
783 | // Tests creating a function template. |
784 | |
785 | CompilerType int_type = m_ast->GetBasicType(type: lldb::eBasicTypeInt); |
786 | clang::TranslationUnitDecl *TU = m_ast->GetTranslationUnitDecl(); |
787 | |
788 | // Prepare the declarations/types we need for the template. |
789 | CompilerType clang_type = |
790 | m_ast->CreateFunctionType(result_type: int_type, args: nullptr, num_args: 0U, is_variadic: false, type_quals: 0U); |
791 | FunctionDecl *func = m_ast->CreateFunctionDeclaration( |
792 | TU, OptionalClangModuleID(), "foo" , clang_type, StorageClass::SC_None, |
793 | false); |
794 | TypeSystemClang::TemplateParameterInfos empty_params; |
795 | |
796 | // Create the actual function template. |
797 | clang::FunctionTemplateDecl *func_template = |
798 | m_ast->CreateFunctionTemplateDecl(TU, OptionalClangModuleID(), func, |
799 | empty_params); |
800 | |
801 | EXPECT_EQ(TU, func_template->getDeclContext()); |
802 | EXPECT_EQ("foo" , func_template->getName()); |
803 | EXPECT_EQ(clang::AccessSpecifier::AS_none, func_template->getAccess()); |
804 | } |
805 | |
806 | TEST_F(TestTypeSystemClang, TestFunctionTemplateInRecordConstruction) { |
807 | // Tests creating a function template inside a record. |
808 | |
809 | CompilerType int_type = m_ast->GetBasicType(type: lldb::eBasicTypeInt); |
810 | clang::TranslationUnitDecl *TU = m_ast->GetTranslationUnitDecl(); |
811 | |
812 | // Create a record we can put the function template int. |
813 | CompilerType record_type = |
814 | clang_utils::createRecordWithField(ast&: *m_ast, record_name: "record" , field_type: int_type, field_name: "field" ); |
815 | clang::TagDecl *record = ClangUtil::GetAsTagDecl(type: record_type); |
816 | |
817 | // Prepare the declarations/types we need for the template. |
818 | CompilerType clang_type = |
819 | m_ast->CreateFunctionType(result_type: int_type, args: nullptr, num_args: 0U, is_variadic: false, type_quals: 0U); |
820 | // We create the FunctionDecl for the template in the TU DeclContext because: |
821 | // 1. FunctionDecls can't be in a Record (only CXXMethodDecls can). |
822 | // 2. It is mirroring the behavior of DWARFASTParserClang::ParseSubroutine. |
823 | FunctionDecl *func = m_ast->CreateFunctionDeclaration( |
824 | TU, OptionalClangModuleID(), "foo" , clang_type, StorageClass::SC_None, |
825 | false); |
826 | TypeSystemClang::TemplateParameterInfos empty_params; |
827 | |
828 | // Create the actual function template. |
829 | clang::FunctionTemplateDecl *func_template = |
830 | m_ast->CreateFunctionTemplateDecl(record, OptionalClangModuleID(), func, |
831 | empty_params); |
832 | |
833 | EXPECT_EQ(record, func_template->getDeclContext()); |
834 | EXPECT_EQ("foo" , func_template->getName()); |
835 | EXPECT_EQ(clang::AccessSpecifier::AS_public, func_template->getAccess()); |
836 | } |
837 | |
838 | TEST_F(TestTypeSystemClang, TestDeletingImplicitCopyCstrDueToMoveCStr) { |
839 | // We need to simulate this behavior in our AST that we construct as we don't |
840 | // have a Sema instance that can do this for us: |
841 | // C++11 [class.copy]p7, p18: |
842 | // If the class definition declares a move constructor or move assignment |
843 | // operator, an implicitly declared copy constructor or copy assignment |
844 | // operator is defined as deleted. |
845 | |
846 | // Create a record and start defining it. |
847 | llvm::StringRef class_name = "S" ; |
848 | CompilerType t = clang_utils::createRecord(ast&: *m_ast, name: class_name); |
849 | m_ast->StartTagDeclarationDefinition(type: t); |
850 | |
851 | // Create a move constructor that will delete the implicit copy constructor. |
852 | CompilerType return_type = m_ast->GetBasicType(type: lldb::eBasicTypeVoid); |
853 | CompilerType param_type = t.GetRValueReferenceType(); |
854 | CompilerType function_type = |
855 | m_ast->CreateFunctionType(result_type: return_type, args: ¶m_type, /*num_params*/ num_args: 1, |
856 | /*variadic=*/is_variadic: false, /*quals*/ type_quals: 0U); |
857 | bool is_virtual = false; |
858 | bool is_static = false; |
859 | bool is_inline = false; |
860 | bool is_explicit = true; |
861 | bool is_attr_used = false; |
862 | bool is_artificial = false; |
863 | m_ast->AddMethodToCXXRecordType( |
864 | type: t.GetOpaqueQualType(), name: class_name, mangled_name: nullptr, method_type: function_type, |
865 | access: lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, |
866 | is_explicit, is_attr_used, is_artificial); |
867 | |
868 | // Complete the definition and check the created record. |
869 | m_ast->CompleteTagDeclarationDefinition(type: t); |
870 | auto *record = llvm::cast<CXXRecordDecl>(Val: ClangUtil::GetAsTagDecl(type: t)); |
871 | // We can't call defaultedCopyConstructorIsDeleted() as this requires that |
872 | // the Decl passes through Sema which will actually compute this field. |
873 | // Instead we check that there is no copy constructor declared by the user |
874 | // which only leaves a non-deleted defaulted copy constructor as an option |
875 | // that our record will have no simple copy constructor. |
876 | EXPECT_FALSE(record->hasUserDeclaredCopyConstructor()); |
877 | EXPECT_FALSE(record->hasSimpleCopyConstructor()); |
878 | } |
879 | |
880 | TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) { |
881 | // Tests that we don't delete the a user-defined copy constructor when |
882 | // a move constructor is provided. |
883 | // See also the TestDeletingImplicitCopyCstrDueToMoveCStr test. |
884 | llvm::StringRef class_name = "S" ; |
885 | CompilerType t = clang_utils::createRecord(ast&: *m_ast, name: class_name); |
886 | m_ast->StartTagDeclarationDefinition(type: t); |
887 | |
888 | CompilerType return_type = m_ast->GetBasicType(type: lldb::eBasicTypeVoid); |
889 | bool is_virtual = false; |
890 | bool is_static = false; |
891 | bool is_inline = false; |
892 | bool is_explicit = true; |
893 | bool is_attr_used = false; |
894 | bool is_artificial = false; |
895 | // Create a move constructor. |
896 | { |
897 | CompilerType param_type = t.GetRValueReferenceType(); |
898 | CompilerType function_type = |
899 | m_ast->CreateFunctionType(result_type: return_type, args: ¶m_type, /*num_params*/ num_args: 1, |
900 | /*variadic=*/is_variadic: false, /*quals*/ type_quals: 0U); |
901 | m_ast->AddMethodToCXXRecordType( |
902 | type: t.GetOpaqueQualType(), name: class_name, mangled_name: nullptr, method_type: function_type, |
903 | access: lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, |
904 | is_explicit, is_attr_used, is_artificial); |
905 | } |
906 | // Create a copy constructor. |
907 | { |
908 | CompilerType param_type = t.GetLValueReferenceType().AddConstModifier(); |
909 | CompilerType function_type = |
910 | m_ast->CreateFunctionType(result_type: return_type, args: ¶m_type, /*num_params*/ num_args: 1, |
911 | /*variadic=*/is_variadic: false, /*quals*/ type_quals: 0U); |
912 | m_ast->AddMethodToCXXRecordType( |
913 | type: t.GetOpaqueQualType(), name: class_name, mangled_name: nullptr, method_type: function_type, |
914 | access: lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, |
915 | is_explicit, is_attr_used, is_artificial); |
916 | } |
917 | |
918 | // Complete the definition and check the created record. |
919 | m_ast->CompleteTagDeclarationDefinition(type: t); |
920 | auto *record = llvm::cast<CXXRecordDecl>(Val: ClangUtil::GetAsTagDecl(type: t)); |
921 | EXPECT_TRUE(record->hasUserDeclaredCopyConstructor()); |
922 | } |
923 | |
924 | TEST_F(TestTypeSystemClang, AddMethodToObjCObjectType) { |
925 | // Create an interface decl and mark it as having external storage. |
926 | CompilerType c = m_ast->CreateObjCClass("A" , m_ast->GetTranslationUnitDecl(), |
927 | OptionalClangModuleID(), |
928 | /*IsForwardDecl*/ false, |
929 | /*IsInternal*/ false); |
930 | ObjCInterfaceDecl *interface = m_ast->GetAsObjCInterfaceDecl(type: c); |
931 | m_ast->SetHasExternalStorage(type: c.GetOpaqueQualType(), has_extern: true); |
932 | EXPECT_TRUE(interface->hasExternalLexicalStorage()); |
933 | |
934 | // Add a method to the interface. |
935 | std::vector<CompilerType> args; |
936 | CompilerType func_type = |
937 | m_ast->CreateFunctionType(result_type: m_ast->GetBasicType(type: lldb::eBasicTypeInt), |
938 | args: args.data(), num_args: args.size(), /*variadic*/ is_variadic: false, |
939 | /*quals*/ type_quals: 0, cc: clang::CallingConv::CC_C); |
940 | bool variadic = false; |
941 | bool artificial = false; |
942 | bool objc_direct = false; |
943 | clang::ObjCMethodDecl *method = TypeSystemClang::AddMethodToObjCObjectType( |
944 | type: c, name: "-[A foo]" , method_compiler_type: func_type, is_artificial: artificial, is_variadic: variadic, is_objc_direct_call: objc_direct); |
945 | ASSERT_NE(method, nullptr); |
946 | |
947 | // The interface decl should still have external lexical storage. |
948 | EXPECT_TRUE(interface->hasExternalLexicalStorage()); |
949 | |
950 | // Test some properties of the created ObjCMethodDecl. |
951 | EXPECT_FALSE(method->isVariadic()); |
952 | EXPECT_TRUE(method->isImplicit()); |
953 | EXPECT_FALSE(method->isDirectMethod()); |
954 | EXPECT_EQ(method->getDeclName().getObjCSelector().getAsString(), "foo" ); |
955 | } |
956 | |
957 | TEST_F(TestTypeSystemClang, GetFullyUnqualifiedType) { |
958 | CompilerType bool_ = m_ast->GetBasicType(type: eBasicTypeBool); |
959 | CompilerType cv_bool = bool_.AddConstModifier().AddVolatileModifier(); |
960 | |
961 | // const volatile bool -> bool |
962 | EXPECT_EQ(bool_, cv_bool.GetFullyUnqualifiedType()); |
963 | |
964 | // const volatile bool[47] -> bool[47] |
965 | EXPECT_EQ(bool_.GetArrayType(47), |
966 | cv_bool.GetArrayType(47).GetFullyUnqualifiedType()); |
967 | |
968 | // const volatile bool[47][42] -> bool[47][42] |
969 | EXPECT_EQ( |
970 | bool_.GetArrayType(42).GetArrayType(47), |
971 | cv_bool.GetArrayType(42).GetArrayType(47).GetFullyUnqualifiedType()); |
972 | |
973 | // const volatile bool * -> bool * |
974 | EXPECT_EQ(bool_.GetPointerType(), |
975 | cv_bool.GetPointerType().GetFullyUnqualifiedType()); |
976 | |
977 | // const volatile bool *[47] -> bool *[47] |
978 | EXPECT_EQ( |
979 | bool_.GetPointerType().GetArrayType(47), |
980 | cv_bool.GetPointerType().GetArrayType(47).GetFullyUnqualifiedType()); |
981 | } |
982 | |
983 | TEST(TestScratchTypeSystemClang, InferSubASTFromLangOpts) { |
984 | LangOptions lang_opts; |
985 | EXPECT_EQ( |
986 | ScratchTypeSystemClang::DefaultAST, |
987 | ScratchTypeSystemClang::InferIsolatedASTKindFromLangOpts(lang_opts)); |
988 | |
989 | lang_opts.Modules = true; |
990 | EXPECT_EQ( |
991 | ScratchTypeSystemClang::IsolatedASTKind::CppModules, |
992 | ScratchTypeSystemClang::InferIsolatedASTKindFromLangOpts(lang_opts)); |
993 | } |
994 | |
995 | TEST_F(TestTypeSystemClang, GetDeclContextByNameWhenMissingSymbolFile) { |
996 | // Test that a type system without a symbol file is handled gracefully. |
997 | std::vector<CompilerDecl> decls = |
998 | m_ast->DeclContextFindDeclByName(opaque_decl_ctx: nullptr, name: ConstString("SomeName" ), ignore_using_decls: true); |
999 | |
1000 | EXPECT_TRUE(decls.empty()); |
1001 | } |
1002 | |