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