1//===-- PythonDataObjectsTests.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 "gtest/gtest.h"
10
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
13#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
14#include "llvm/Support/FileSystem.h"
15#include "llvm/Support/Path.h"
16#include "llvm/Testing/Support/Error.h"
17
18#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
19#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
20#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
21#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
22#include "TestingSupport/TestUtilities.h"
23#include "lldb/Core/Address.h"
24#include "lldb/Core/Module.h"
25#include "lldb/Core/ModuleSpec.h"
26#include "lldb/Host/FileSystem.h"
27#include "lldb/Host/HostInfo.h"
28#include "lldb/Symbol/CompileUnit.h"
29#include "lldb/Symbol/LineTable.h"
30#include "lldb/Symbol/TypeMap.h"
31#include "lldb/Utility/ArchSpec.h"
32#include "lldb/Utility/FileSpec.h"
33
34#if defined(_WIN32)
35#include "lldb/Host/windows/windows.h"
36#include <objbase.h>
37#endif
38
39#include <algorithm>
40
41using namespace lldb_private;
42
43class SymbolFilePDBTests : public testing::Test {
44public:
45 void SetUp() override {
46// Initialize and TearDown the plugin every time, so we get a brand new
47// AST every time so that modifications to the AST from each test don't
48// leak into the next test.
49#if defined(_WIN32)
50 ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
51#endif
52
53 FileSystem::Initialize();
54 HostInfo::Initialize();
55 ObjectFilePECOFF::Initialize();
56 plugin::dwarf::SymbolFileDWARF::Initialize();
57 TypeSystemClang::Initialize();
58 SymbolFilePDB::Initialize();
59
60 m_pdb_test_exe = GetInputFilePath(name: "test-pdb.exe");
61 m_types_test_exe = GetInputFilePath(name: "test-pdb-types.exe");
62 }
63
64 void TearDown() override {
65 SymbolFilePDB::Terminate();
66 TypeSystemClang::Initialize();
67 plugin::dwarf::SymbolFileDWARF::Terminate();
68 ObjectFilePECOFF::Terminate();
69 HostInfo::Terminate();
70 FileSystem::Terminate();
71
72#if defined(_WIN32)
73 ::CoUninitialize();
74#endif
75 }
76
77protected:
78 std::string m_pdb_test_exe;
79 std::string m_types_test_exe;
80
81 bool FileSpecMatchesAsBaseOrFull(const FileSpec &left,
82 const FileSpec &right) const {
83 // If the filenames don't match, the paths can't be equal
84 if (!left.FileEquals(other: right))
85 return false;
86 // If BOTH have a directory, also compare the directories.
87 if (left.GetDirectory() && right.GetDirectory())
88 return left.DirectoryEquals(other: right);
89
90 // If one has a directory but not the other, they match.
91 return true;
92 }
93
94 void VerifyLineEntry(lldb::ModuleSP module, const SymbolContext &sc,
95 const FileSpec &spec, LineTable &lt, uint32_t line,
96 lldb::addr_t addr) {
97 LineEntry entry;
98 Address address;
99 EXPECT_TRUE(module->ResolveFileAddress(addr, address));
100
101 EXPECT_TRUE(lt.FindLineEntryByAddress(address, entry));
102 EXPECT_EQ(line, entry.line);
103 EXPECT_EQ(address, entry.range.GetBaseAddress());
104
105 EXPECT_TRUE(FileSpecMatchesAsBaseOrFull(spec, entry.GetFile()));
106 }
107
108 bool ContainsCompileUnit(const SymbolContextList &sc_list,
109 const FileSpec &spec) const {
110 for (size_t i = 0; i < sc_list.GetSize(); ++i) {
111 const SymbolContext &sc = sc_list[i];
112 if (FileSpecMatchesAsBaseOrFull(left: sc.comp_unit->GetPrimaryFile(), right: spec))
113 return true;
114 }
115 return false;
116 }
117
118 uint64_t GetGlobalConstantInteger(llvm::pdb::IPDBSession &session,
119 llvm::StringRef var) const {
120 auto global = session.getGlobalScope();
121 auto results =
122 global->findChildren(Type: llvm::pdb::PDB_SymType::Data, Name: var,
123 Flags: llvm::pdb::PDB_NameSearchFlags::NS_Default);
124 uint32_t count = results->getChildCount();
125 if (count == 0)
126 return -1;
127
128 auto item = results->getChildAtIndex(Index: 0);
129 auto symbol = llvm::dyn_cast<llvm::pdb::PDBSymbolData>(Val: item.get());
130 if (!symbol)
131 return -1;
132 llvm::pdb::Variant value = symbol->getValue();
133 switch (value.Type) {
134 case llvm::pdb::PDB_VariantType::Int16:
135 return value.Value.Int16;
136 case llvm::pdb::PDB_VariantType::Int32:
137 return value.Value.Int32;
138 case llvm::pdb::PDB_VariantType::UInt16:
139 return value.Value.UInt16;
140 case llvm::pdb::PDB_VariantType::UInt32:
141 return value.Value.UInt32;
142 default:
143 return 0;
144 }
145 }
146};
147
148TEST_F(SymbolFilePDBTests, TestAbilitiesForPDB) {
149 // Test that when we have PDB debug info, SymbolFilePDB is used.
150 FileSpec fspec(m_pdb_test_exe);
151 ArchSpec aspec("i686-pc-windows");
152 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
153
154 SymbolFile *symfile = module->GetSymbolFile();
155 EXPECT_NE(nullptr, symfile);
156 EXPECT_EQ(symfile->GetPluginName(), SymbolFilePDB::GetPluginNameStatic());
157
158 uint32_t expected_abilities = SymbolFile::kAllAbilities;
159 EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
160}
161
162TEST_F(SymbolFilePDBTests, TestResolveSymbolContextBasename) {
163 // Test that attempting to call ResolveSymbolContext with only a basename
164 // finds all full paths
165 // with the same basename
166 FileSpec fspec(m_pdb_test_exe);
167 ArchSpec aspec("i686-pc-windows");
168 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
169
170 SymbolFile *symfile = module->GetSymbolFile();
171
172 FileSpec header_spec("test-pdb.cpp");
173 SymbolContextList sc_list;
174 SourceLocationSpec location_spec(header_spec, /*line=*/0);
175 uint32_t result_count = symfile->ResolveSymbolContext(
176 src_location_spec: location_spec, resolve_scope: lldb::eSymbolContextCompUnit, sc_list);
177 EXPECT_EQ(1u, result_count);
178 EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
179}
180
181TEST_F(SymbolFilePDBTests, TestResolveSymbolContextFullPath) {
182 // Test that attempting to call ResolveSymbolContext with a full path only
183 // finds the one source
184 // file that matches the full path.
185 FileSpec fspec(m_pdb_test_exe);
186 ArchSpec aspec("i686-pc-windows");
187 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
188
189 SymbolFile *symfile = module->GetSymbolFile();
190
191 FileSpec header_spec(
192 R"spec(D:\src\llvm\tools\lldb\unittests\SymbolFile\PDB\Inputs\test-pdb.cpp)spec");
193 SymbolContextList sc_list;
194 SourceLocationSpec location_spec(header_spec, /*line=*/0);
195 uint32_t result_count = symfile->ResolveSymbolContext(
196 src_location_spec: location_spec, resolve_scope: lldb::eSymbolContextCompUnit, sc_list);
197 EXPECT_GE(1u, result_count);
198 EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
199}
200
201TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithInlines) {
202 // Test that when looking up a header file via ResolveSymbolContext (i.e. a
203 // file that was not by itself
204 // compiled, but only contributes to the combined code of other source files),
205 // a SymbolContext is returned
206 // for each compiland which has line contributions from the requested header.
207 FileSpec fspec(m_pdb_test_exe);
208 ArchSpec aspec("i686-pc-windows");
209 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
210
211 SymbolFile *symfile = module->GetSymbolFile();
212
213 FileSpec header_specs[] = {FileSpec("test-pdb.h"),
214 FileSpec("test-pdb-nested.h")};
215 FileSpec main_cpp_spec("test-pdb.cpp");
216 FileSpec alt_cpp_spec("test-pdb-alt.cpp");
217 for (const auto &hspec : header_specs) {
218 SymbolContextList sc_list;
219 SourceLocationSpec location_spec(hspec, /*line=*/0, /*column=*/std::nullopt,
220 /*check_inlines=*/true);
221 uint32_t result_count = symfile->ResolveSymbolContext(
222 src_location_spec: location_spec, resolve_scope: lldb::eSymbolContextCompUnit, sc_list);
223 EXPECT_EQ(2u, result_count);
224 EXPECT_TRUE(ContainsCompileUnit(sc_list, main_cpp_spec));
225 EXPECT_TRUE(ContainsCompileUnit(sc_list, alt_cpp_spec));
226 }
227}
228
229TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithNoInlines) {
230 // Test that when looking up a header file via ResolveSymbolContext (i.e. a
231 // file that was not by itself
232 // compiled, but only contributes to the combined code of other source files),
233 // that if check_inlines
234 // is false, no SymbolContexts are returned.
235 FileSpec fspec(m_pdb_test_exe);
236 ArchSpec aspec("i686-pc-windows");
237 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
238
239 SymbolFile *symfile = module->GetSymbolFile();
240
241 FileSpec header_specs[] = {FileSpec("test-pdb.h"),
242 FileSpec("test-pdb-nested.h")};
243 for (const auto &hspec : header_specs) {
244 SymbolContextList sc_list;
245 SourceLocationSpec location_spec(hspec, /*line=*/0);
246 uint32_t result_count = symfile->ResolveSymbolContext(
247 src_location_spec: location_spec, resolve_scope: lldb::eSymbolContextCompUnit, sc_list);
248 EXPECT_EQ(0u, result_count);
249 }
250}
251
252TEST_F(SymbolFilePDBTests, TestLineTablesMatchAll) {
253 // Test that when calling ResolveSymbolContext with a line number of 0, all
254 // line entries from
255 // the specified files are returned.
256 FileSpec fspec(m_pdb_test_exe);
257 ArchSpec aspec("i686-pc-windows");
258 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
259
260 SymbolFile *symfile = module->GetSymbolFile();
261
262 FileSpec source_file("test-pdb.cpp");
263 FileSpec header1("test-pdb.h");
264 FileSpec header2("test-pdb-nested.h");
265 uint32_t cus = symfile->GetNumCompileUnits();
266 EXPECT_EQ(2u, cus);
267
268 SymbolContextList sc_list;
269 lldb::SymbolContextItem scope =
270 lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
271
272 SourceLocationSpec location_spec(
273 source_file, /*line=*/0, /*column=*/std::nullopt, /*check_inlines=*/true);
274 uint32_t count = symfile->ResolveSymbolContext(src_location_spec: location_spec, resolve_scope: scope, sc_list);
275 EXPECT_EQ(1u, count);
276 SymbolContext sc;
277 EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
278
279 LineTable *lt = sc.comp_unit->GetLineTable();
280 EXPECT_NE(nullptr, lt);
281 count = lt->GetSize();
282 // We expect one extra entry for termination (per function)
283 EXPECT_EQ(16u, count);
284
285 VerifyLineEntry(module, sc, spec: source_file, lt&: *lt, line: 7, addr: 0x401040);
286 VerifyLineEntry(module, sc, spec: source_file, lt&: *lt, line: 8, addr: 0x401043);
287 VerifyLineEntry(module, sc, spec: source_file, lt&: *lt, line: 9, addr: 0x401045);
288
289 VerifyLineEntry(module, sc, spec: source_file, lt&: *lt, line: 13, addr: 0x401050);
290 VerifyLineEntry(module, sc, spec: source_file, lt&: *lt, line: 14, addr: 0x401054);
291 VerifyLineEntry(module, sc, spec: source_file, lt&: *lt, line: 15, addr: 0x401070);
292
293 VerifyLineEntry(module, sc, spec: header1, lt&: *lt, line: 9, addr: 0x401090);
294 VerifyLineEntry(module, sc, spec: header1, lt&: *lt, line: 10, addr: 0x401093);
295 VerifyLineEntry(module, sc, spec: header1, lt&: *lt, line: 11, addr: 0x4010a2);
296
297 VerifyLineEntry(module, sc, spec: header2, lt&: *lt, line: 5, addr: 0x401080);
298 VerifyLineEntry(module, sc, spec: header2, lt&: *lt, line: 6, addr: 0x401083);
299 VerifyLineEntry(module, sc, spec: header2, lt&: *lt, line: 7, addr: 0x401089);
300}
301
302TEST_F(SymbolFilePDBTests, TestLineTablesMatchSpecific) {
303 // Test that when calling ResolveSymbolContext with a specific line number,
304 // only line entries
305 // which match the requested line are returned.
306 FileSpec fspec(m_pdb_test_exe);
307 ArchSpec aspec("i686-pc-windows");
308 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
309
310 SymbolFile *symfile = module->GetSymbolFile();
311
312 FileSpec source_file("test-pdb.cpp");
313 FileSpec header1("test-pdb.h");
314 FileSpec header2("test-pdb-nested.h");
315 uint32_t cus = symfile->GetNumCompileUnits();
316 EXPECT_EQ(2u, cus);
317
318 SymbolContextList sc_list;
319 lldb::SymbolContextItem scope =
320 lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
321
322 // First test with line 7, and verify that only line 7 entries are added.
323 SourceLocationSpec location_spec(
324 source_file, /*line=*/7, /*column=*/std::nullopt, /*check_inlines=*/true);
325 uint32_t count = symfile->ResolveSymbolContext(src_location_spec: location_spec, resolve_scope: scope, sc_list);
326 EXPECT_EQ(1u, count);
327 SymbolContext sc;
328 EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
329
330 LineTable *lt = sc.comp_unit->GetLineTable();
331 EXPECT_NE(nullptr, lt);
332 count = lt->GetSize();
333 // We expect one extra entry for termination
334 EXPECT_EQ(3u, count);
335
336 VerifyLineEntry(module, sc, spec: source_file, lt&: *lt, line: 7, addr: 0x401040);
337 VerifyLineEntry(module, sc, spec: header2, lt&: *lt, line: 7, addr: 0x401089);
338
339 sc_list.Clear();
340 // Then test with line 9, and verify that only line 9 entries are added.
341 location_spec = SourceLocationSpec(
342 source_file, /*line=*/9, /*column=*/std::nullopt, /*check_inlines=*/true);
343 count = symfile->ResolveSymbolContext(src_location_spec: location_spec, resolve_scope: scope, sc_list);
344 EXPECT_EQ(1u, count);
345 EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
346
347 lt = sc.comp_unit->GetLineTable();
348 EXPECT_NE(nullptr, lt);
349 count = lt->GetSize();
350 // We expect one extra entry for termination
351 EXPECT_EQ(3u, count);
352
353 VerifyLineEntry(module, sc, spec: source_file, lt&: *lt, line: 9, addr: 0x401045);
354 VerifyLineEntry(module, sc, spec: header1, lt&: *lt, line: 9, addr: 0x401090);
355}
356
357TEST_F(SymbolFilePDBTests, TestSimpleClassTypes) {
358 FileSpec fspec(m_types_test_exe);
359 ArchSpec aspec("i686-pc-windows");
360 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
361
362 SymbolFilePDB *symfile =
363 static_cast<SymbolFilePDB *>(module->GetSymbolFile());
364 llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
365 TypeResults query_results;
366 symfile->FindTypes(match: TypeQuery("Class"), results&: query_results);
367 TypeMap &results = query_results.GetTypeMap();
368 EXPECT_EQ(1u, results.GetSize());
369 lldb::TypeSP udt_type = results.GetTypeAtIndex(idx: 0);
370 EXPECT_EQ(ConstString("Class"), udt_type->GetName());
371 CompilerType compiler_type = udt_type->GetForwardCompilerType();
372 EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
373 EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_Class"),
374 udt_type->GetByteSize(nullptr));
375}
376
377TEST_F(SymbolFilePDBTests, TestNestedClassTypes) {
378 FileSpec fspec(m_types_test_exe);
379 ArchSpec aspec("i686-pc-windows");
380 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
381
382 SymbolFilePDB *symfile =
383 static_cast<SymbolFilePDB *>(module->GetSymbolFile());
384 llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
385
386 auto clang_ast_ctx_or_err =
387 symfile->GetTypeSystemForLanguage(language: lldb::eLanguageTypeC_plus_plus);
388 ASSERT_THAT_EXPECTED(clang_ast_ctx_or_err, llvm::Succeeded());
389
390 auto clang_ast_ctx =
391 llvm::dyn_cast_or_null<TypeSystemClang>(Val: clang_ast_ctx_or_err->get());
392 EXPECT_NE(nullptr, clang_ast_ctx);
393
394 TypeResults query_results;
395 symfile->FindTypes(match: TypeQuery("Class"), results&: query_results);
396 TypeMap &results = query_results.GetTypeMap();
397
398 EXPECT_EQ(1u, results.GetSize());
399
400 auto Class = results.GetTypeAtIndex(idx: 0);
401 EXPECT_TRUE(Class);
402 EXPECT_TRUE(Class->IsValidType());
403
404 auto ClassCompilerType = Class->GetFullCompilerType();
405 EXPECT_TRUE(ClassCompilerType.IsValid());
406
407 auto ClassDeclCtx = clang_ast_ctx->GetDeclContextForType(type: ClassCompilerType);
408 EXPECT_NE(nullptr, ClassDeclCtx);
409
410 // There are two symbols for nested classes: one belonging to enclosing class
411 // and one is global. We process correctly this case and create the same
412 // compiler type for both, but `FindTypes` may return more than one type
413 // (with the same compiler type) because the symbols have different IDs.
414
415 auto ClassCompilerDeclCtx = CompilerDeclContext(clang_ast_ctx, ClassDeclCtx);
416 TypeResults query_results_nested;
417 symfile->FindTypes(
418 match: TypeQuery(ClassCompilerDeclCtx, ConstString("NestedClass")),
419 results&: query_results_nested);
420 TypeMap &more_results = query_results_nested.GetTypeMap();
421 EXPECT_LE(1u, more_results.GetSize());
422
423 lldb::TypeSP udt_type = more_results.GetTypeAtIndex(idx: 0);
424 EXPECT_EQ(ConstString("NestedClass"), udt_type->GetName());
425
426 CompilerType compiler_type = udt_type->GetForwardCompilerType();
427 EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
428
429 EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NestedClass"),
430 udt_type->GetByteSize(nullptr));
431}
432
433TEST_F(SymbolFilePDBTests, TestClassInNamespace) {
434 FileSpec fspec(m_types_test_exe);
435 ArchSpec aspec("i686-pc-windows");
436 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
437
438 SymbolFilePDB *symfile =
439 static_cast<SymbolFilePDB *>(module->GetSymbolFile());
440 llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
441 auto clang_ast_ctx_or_err =
442 symfile->GetTypeSystemForLanguage(language: lldb::eLanguageTypeC_plus_plus);
443 ASSERT_THAT_EXPECTED(clang_ast_ctx_or_err, llvm::Succeeded());
444
445 auto clang_ast_ctx =
446 llvm::dyn_cast_or_null<TypeSystemClang>(Val: clang_ast_ctx_or_err->get());
447 EXPECT_NE(nullptr, clang_ast_ctx);
448
449 clang::ASTContext &ast_ctx = clang_ast_ctx->getASTContext();
450
451 auto tu = ast_ctx.getTranslationUnitDecl();
452 EXPECT_NE(nullptr, tu);
453
454 symfile->ParseDeclsForContext(CompilerDeclContext(
455 clang_ast_ctx, static_cast<clang::DeclContext *>(tu)));
456
457 auto ns_namespace_decl_ctx =
458 symfile->FindNamespace(name: ConstString("NS"), parent_decl_ctx: CompilerDeclContext(), only_root_namespaces: true);
459 EXPECT_TRUE(ns_namespace_decl_ctx.IsValid());
460
461 TypeResults query_results;
462 symfile->FindTypes(match: TypeQuery(ns_namespace_decl_ctx, ConstString("NSClass")),
463 results&: query_results);
464 TypeMap &results = query_results.GetTypeMap();
465 EXPECT_EQ(1u, results.GetSize());
466
467 lldb::TypeSP udt_type = results.GetTypeAtIndex(idx: 0);
468 EXPECT_EQ(ConstString("NSClass"), udt_type->GetName());
469
470 CompilerType compiler_type = udt_type->GetForwardCompilerType();
471 EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
472
473 EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NSClass"),
474 udt_type->GetByteSize(nullptr));
475}
476
477TEST_F(SymbolFilePDBTests, TestEnumTypes) {
478 FileSpec fspec(m_types_test_exe);
479 ArchSpec aspec("i686-pc-windows");
480 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
481
482 SymbolFilePDB *symfile =
483 static_cast<SymbolFilePDB *>(module->GetSymbolFile());
484 llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
485 const char *EnumsToCheck[] = {"Enum", "ShortEnum"};
486 for (auto Enum : EnumsToCheck) {
487
488 TypeResults query_results;
489 symfile->FindTypes(match: TypeQuery(Enum), results&: query_results);
490 TypeMap &results = query_results.GetTypeMap();
491 EXPECT_EQ(1u, results.GetSize());
492 lldb::TypeSP enum_type = results.GetTypeAtIndex(idx: 0);
493 EXPECT_EQ(ConstString(Enum), enum_type->GetName());
494 CompilerType compiler_type = enum_type->GetFullCompilerType();
495 EXPECT_TRUE(TypeSystemClang::IsEnumType(compiler_type.GetOpaqueQualType()));
496 clang::EnumDecl *enum_decl = TypeSystemClang::GetAsEnumDecl(type: compiler_type);
497 EXPECT_NE(nullptr, enum_decl);
498 EXPECT_EQ(2, std::distance(enum_decl->enumerator_begin(),
499 enum_decl->enumerator_end()));
500
501 std::string sizeof_var = "sizeof_";
502 sizeof_var.append(s: Enum);
503 EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
504 enum_type->GetByteSize(nullptr));
505 }
506}
507
508TEST_F(SymbolFilePDBTests, TestArrayTypes) {
509 // In order to get this test working, we need to support lookup by symbol
510 // name. Because array
511 // types themselves do not have names, only the symbols have names (i.e. the
512 // name of the array).
513}
514
515TEST_F(SymbolFilePDBTests, TestFunctionTypes) {
516 // In order to get this test working, we need to support lookup by symbol
517 // name. Because array
518 // types themselves do not have names, only the symbols have names (i.e. the
519 // name of the array).
520}
521
522TEST_F(SymbolFilePDBTests, TestTypedefs) {
523 FileSpec fspec(m_types_test_exe);
524 ArchSpec aspec("i686-pc-windows");
525 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
526
527 SymbolFilePDB *symfile =
528 static_cast<SymbolFilePDB *>(module->GetSymbolFile());
529 llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
530
531 const char *TypedefsToCheck[] = {"ClassTypedef", "NSClassTypedef",
532 "FuncPointerTypedef",
533 "VariadicFuncPointerTypedef"};
534 for (auto Typedef : TypedefsToCheck) {
535 TypeResults query_results;
536 symfile->FindTypes(match: TypeQuery(Typedef), results&: query_results);
537 TypeMap &results = query_results.GetTypeMap();
538 EXPECT_EQ(1u, results.GetSize());
539 lldb::TypeSP typedef_type = results.GetTypeAtIndex(idx: 0);
540 EXPECT_EQ(ConstString(Typedef), typedef_type->GetName());
541 CompilerType compiler_type = typedef_type->GetFullCompilerType();
542 auto clang_type_system =
543 compiler_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
544 EXPECT_TRUE(
545 clang_type_system->IsTypedefType(compiler_type.GetOpaqueQualType()));
546
547 std::string sizeof_var = "sizeof_";
548 sizeof_var.append(s: Typedef);
549 EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
550 typedef_type->GetByteSize(nullptr));
551 }
552}
553
554TEST_F(SymbolFilePDBTests, TestRegexNameMatch) {
555 FileSpec fspec(m_types_test_exe);
556 ArchSpec aspec("i686-pc-windows");
557 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
558
559 SymbolFilePDB *symfile =
560 static_cast<SymbolFilePDB *>(module->GetSymbolFile());
561 TypeMap results;
562
563 symfile->FindTypesByRegex(regex: RegularExpression(".*"), max_matches: 0, types&: results);
564 EXPECT_GT(results.GetSize(), 1u);
565
566 // We expect no exception thrown if the given regex can't be compiled
567 results.Clear();
568 symfile->FindTypesByRegex(regex: RegularExpression("**"), max_matches: 0, types&: results);
569 EXPECT_EQ(0u, results.GetSize());
570}
571
572TEST_F(SymbolFilePDBTests, TestMaxMatches) {
573 FileSpec fspec(m_types_test_exe);
574 ArchSpec aspec("i686-pc-windows");
575 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
576
577 SymbolFilePDB *symfile =
578 static_cast<SymbolFilePDB *>(module->GetSymbolFile());
579
580 // Make a type query object we can use for all types and for one type
581 TypeQuery query("NestedClass");
582 {
583 // Find all types that match
584 TypeResults query_results;
585 symfile->FindTypes(match: query, results&: query_results);
586 TypeMap &results = query_results.GetTypeMap();
587 // We expect to find Class::NestedClass and ClassTypedef::NestedClass.
588 EXPECT_EQ(results.GetSize(), 2u);
589 }
590 {
591 // Find a single type that matches
592 query.SetFindOne(true);
593 TypeResults query_results;
594 symfile->FindTypes(match: query, results&: query_results);
595 TypeMap &results = query_results.GetTypeMap();
596 EXPECT_EQ(results.GetSize(), 1u);
597 }
598}
599
600TEST_F(SymbolFilePDBTests, TestNullName) {
601 FileSpec fspec(m_types_test_exe);
602 ArchSpec aspec("i686-pc-windows");
603 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
604
605 SymbolFilePDB *symfile =
606 static_cast<SymbolFilePDB *>(module->GetSymbolFile());
607
608 TypeResults query_results;
609 symfile->FindTypes(match: TypeQuery(llvm::StringRef()), results&: query_results);
610 TypeMap &results = query_results.GetTypeMap();
611 EXPECT_EQ(0u, results.GetSize());
612}
613
614TEST_F(SymbolFilePDBTests, TestFindSymbolsWithNameAndType) {
615 FileSpec fspec(m_pdb_test_exe.c_str());
616 ArchSpec aspec("i686-pc-windows");
617 lldb::ModuleSP module = std::make_shared<Module>(args&: fspec, args&: aspec);
618
619 SymbolContextList sc_list;
620 module->FindSymbolsWithNameAndType(name: ConstString("?foo@@YAHH@Z"),
621 symbol_type: lldb::eSymbolTypeAny, sc_list);
622 EXPECT_EQ(1u, sc_list.GetSize());
623
624 SymbolContext sc;
625 EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
626 EXPECT_STREQ("int foo(int)",
627 sc.GetFunctionName(Mangled::ePreferDemangled).AsCString());
628}
629

source code of lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp