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 
41 using namespace lldb_private;
42 
43 class SymbolFilePDBTests : public testing::Test {
44 public:
SetUp()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     SymbolFileDWARF::Initialize();
57     TypeSystemClang::Initialize();
58     SymbolFilePDB::Initialize();
59 
60     m_pdb_test_exe = GetInputFilePath("test-pdb.exe");
61     m_types_test_exe = GetInputFilePath("test-pdb-types.exe");
62   }
63 
TearDown()64   void TearDown() override {
65     SymbolFilePDB::Terminate();
66     TypeSystemClang::Initialize();
67     SymbolFileDWARF::Terminate();
68     ObjectFilePECOFF::Terminate();
69     HostInfo::Terminate();
70     FileSystem::Terminate();
71 
72 #if defined(_WIN32)
73     ::CoUninitialize();
74 #endif
75   }
76 
77 protected:
78   std::string m_pdb_test_exe;
79   std::string m_types_test_exe;
80 
FileSpecMatchesAsBaseOrFull(const FileSpec & left,const FileSpec & right) const81   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(right))
85       return false;
86     // If BOTH have a directory, also compare the directories.
87     if (left.GetDirectory() && right.GetDirectory())
88       return left.DirectoryEquals(right);
89 
90     // If one has a directory but not the other, they match.
91     return true;
92   }
93 
VerifyLineEntry(lldb::ModuleSP module,const SymbolContext & sc,const FileSpec & spec,LineTable & lt,uint32_t line,lldb::addr_t addr)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.file));
106   }
107 
ContainsCompileUnit(const SymbolContextList & sc_list,const FileSpec & spec) const108   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(sc.comp_unit->GetPrimaryFile(), spec))
113         return true;
114     }
115     return false;
116   }
117 
GetGlobalConstantInteger(llvm::pdb::IPDBSession & session,llvm::StringRef var) const118   uint64_t GetGlobalConstantInteger(llvm::pdb::IPDBSession &session,
119                                     llvm::StringRef var) const {
120     auto global = session.getGlobalScope();
121     auto results =
122         global->findChildren(llvm::pdb::PDB_SymType::Data, var,
123                              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(0);
129     auto symbol = llvm::dyn_cast<llvm::pdb::PDBSymbolData>(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 
TEST_F(SymbolFilePDBTests,TestAbilitiesForPDB)148 TEST_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>(fspec, 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 
TEST_F(SymbolFilePDBTests,TestResolveSymbolContextBasename)162 TEST_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>(fspec, 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       location_spec, lldb::eSymbolContextCompUnit, sc_list);
177   EXPECT_EQ(1u, result_count);
178   EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
179 }
180 
TEST_F(SymbolFilePDBTests,TestResolveSymbolContextFullPath)181 TEST_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>(fspec, 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       location_spec, lldb::eSymbolContextCompUnit, sc_list);
197   EXPECT_GE(1u, result_count);
198   EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
199 }
200 
TEST_F(SymbolFilePDBTests,TestLookupOfHeaderFileWithInlines)201 TEST_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>(fspec, 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=*/llvm::None,
220                                      /*check_inlines=*/true);
221     uint32_t result_count = symfile->ResolveSymbolContext(
222         location_spec, 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 
TEST_F(SymbolFilePDBTests,TestLookupOfHeaderFileWithNoInlines)229 TEST_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>(fspec, 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         location_spec, lldb::eSymbolContextCompUnit, sc_list);
248     EXPECT_EQ(0u, result_count);
249   }
250 }
251 
TEST_F(SymbolFilePDBTests,TestLineTablesMatchAll)252 TEST_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>(fspec, 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=*/llvm::None, /*check_inlines=*/true);
274   uint32_t count = symfile->ResolveSymbolContext(location_spec, 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, source_file, *lt, 7, 0x401040);
286   VerifyLineEntry(module, sc, source_file, *lt, 8, 0x401043);
287   VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
288 
289   VerifyLineEntry(module, sc, source_file, *lt, 13, 0x401050);
290   VerifyLineEntry(module, sc, source_file, *lt, 14, 0x401054);
291   VerifyLineEntry(module, sc, source_file, *lt, 15, 0x401070);
292 
293   VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
294   VerifyLineEntry(module, sc, header1, *lt, 10, 0x401093);
295   VerifyLineEntry(module, sc, header1, *lt, 11, 0x4010a2);
296 
297   VerifyLineEntry(module, sc, header2, *lt, 5, 0x401080);
298   VerifyLineEntry(module, sc, header2, *lt, 6, 0x401083);
299   VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
300 }
301 
TEST_F(SymbolFilePDBTests,TestLineTablesMatchSpecific)302 TEST_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>(fspec, 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=*/llvm::None, /*check_inlines=*/true);
325   uint32_t count = symfile->ResolveSymbolContext(location_spec, 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, source_file, *lt, 7, 0x401040);
337   VerifyLineEntry(module, sc, header2, *lt, 7, 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=*/llvm::None, /*check_inlines=*/true);
343   count = symfile->ResolveSymbolContext(location_spec, 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, source_file, *lt, 9, 0x401045);
354   VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
355 }
356 
TEST_F(SymbolFilePDBTests,TestSimpleClassTypes)357 TEST_F(SymbolFilePDBTests, TestSimpleClassTypes) {
358   FileSpec fspec(m_types_test_exe);
359   ArchSpec aspec("i686-pc-windows");
360   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
361 
362   SymbolFilePDB *symfile =
363       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
364   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
365   llvm::DenseSet<SymbolFile *> searched_files;
366   TypeMap results;
367   symfile->FindTypes(ConstString("Class"), CompilerDeclContext(), 0,
368                      searched_files, results);
369   EXPECT_EQ(1u, results.GetSize());
370   lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
371   EXPECT_EQ(ConstString("Class"), udt_type->GetName());
372   CompilerType compiler_type = udt_type->GetForwardCompilerType();
373   EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
374   EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_Class"),
375             udt_type->GetByteSize(nullptr));
376 }
377 
TEST_F(SymbolFilePDBTests,TestNestedClassTypes)378 TEST_F(SymbolFilePDBTests, TestNestedClassTypes) {
379   FileSpec fspec(m_types_test_exe);
380   ArchSpec aspec("i686-pc-windows");
381   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
382 
383   SymbolFilePDB *symfile =
384       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
385   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
386   llvm::DenseSet<SymbolFile *> searched_files;
387   TypeMap results;
388 
389   auto clang_ast_ctx_or_err =
390       symfile->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
391   ASSERT_THAT_EXPECTED(clang_ast_ctx_or_err, llvm::Succeeded());
392 
393   auto clang_ast_ctx =
394       llvm::dyn_cast_or_null<TypeSystemClang>(&clang_ast_ctx_or_err.get());
395   EXPECT_NE(nullptr, clang_ast_ctx);
396 
397   symfile->FindTypes(ConstString("Class"), CompilerDeclContext(), 0,
398                      searched_files, results);
399   EXPECT_EQ(1u, results.GetSize());
400 
401   auto Class = results.GetTypeAtIndex(0);
402   EXPECT_TRUE(Class);
403   EXPECT_TRUE(Class->IsValidType());
404 
405   auto ClassCompilerType = Class->GetFullCompilerType();
406   EXPECT_TRUE(ClassCompilerType.IsValid());
407 
408   auto ClassDeclCtx = clang_ast_ctx->GetDeclContextForType(ClassCompilerType);
409   EXPECT_NE(nullptr, ClassDeclCtx);
410 
411   // There are two symbols for nested classes: one belonging to enclosing class
412   // and one is global. We process correctly this case and create the same
413   // compiler type for both, but `FindTypes` may return more than one type
414   // (with the same compiler type) because the symbols have different IDs.
415 
416   TypeMap more_results;
417   auto ClassCompilerDeclCtx = CompilerDeclContext(clang_ast_ctx, ClassDeclCtx);
418   symfile->FindTypes(ConstString("NestedClass"), ClassCompilerDeclCtx, 0,
419                      searched_files, more_results);
420   EXPECT_LE(1u, more_results.GetSize());
421 
422   lldb::TypeSP udt_type = more_results.GetTypeAtIndex(0);
423   EXPECT_EQ(ConstString("NestedClass"), udt_type->GetName());
424 
425   CompilerType compiler_type = udt_type->GetForwardCompilerType();
426   EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
427 
428   EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NestedClass"),
429             udt_type->GetByteSize(nullptr));
430 }
431 
TEST_F(SymbolFilePDBTests,TestClassInNamespace)432 TEST_F(SymbolFilePDBTests, TestClassInNamespace) {
433   FileSpec fspec(m_types_test_exe);
434   ArchSpec aspec("i686-pc-windows");
435   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
436 
437   SymbolFilePDB *symfile =
438       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
439   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
440   llvm::DenseSet<SymbolFile *> searched_files;
441   TypeMap results;
442 
443   auto clang_ast_ctx_or_err =
444       symfile->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
445   ASSERT_THAT_EXPECTED(clang_ast_ctx_or_err, llvm::Succeeded());
446 
447   auto clang_ast_ctx =
448       llvm::dyn_cast_or_null<TypeSystemClang>(&clang_ast_ctx_or_err.get());
449   EXPECT_NE(nullptr, clang_ast_ctx);
450 
451   clang::ASTContext &ast_ctx = clang_ast_ctx->getASTContext();
452 
453   auto tu = ast_ctx.getTranslationUnitDecl();
454   EXPECT_NE(nullptr, tu);
455 
456   symfile->ParseDeclsForContext(CompilerDeclContext(
457       clang_ast_ctx, static_cast<clang::DeclContext *>(tu)));
458 
459   auto ns_namespace = symfile->FindNamespace(ConstString("NS"), CompilerDeclContext());
460   EXPECT_TRUE(ns_namespace.IsValid());
461 
462   symfile->FindTypes(ConstString("NSClass"), ns_namespace, 0, searched_files,
463                      results);
464   EXPECT_EQ(1u, results.GetSize());
465 
466   lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
467   EXPECT_EQ(ConstString("NSClass"), udt_type->GetName());
468 
469   CompilerType compiler_type = udt_type->GetForwardCompilerType();
470   EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
471 
472   EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NSClass"),
473             udt_type->GetByteSize(nullptr));
474 }
475 
TEST_F(SymbolFilePDBTests,TestEnumTypes)476 TEST_F(SymbolFilePDBTests, TestEnumTypes) {
477   FileSpec fspec(m_types_test_exe);
478   ArchSpec aspec("i686-pc-windows");
479   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
480 
481   SymbolFilePDB *symfile =
482       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
483   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
484   llvm::DenseSet<SymbolFile *> searched_files;
485   const char *EnumsToCheck[] = {"Enum", "ShortEnum"};
486   for (auto Enum : EnumsToCheck) {
487     TypeMap results;
488     symfile->FindTypes(ConstString(Enum), CompilerDeclContext(), 0,
489                        searched_files, results);
490     EXPECT_EQ(1u, results.GetSize());
491     lldb::TypeSP enum_type = results.GetTypeAtIndex(0);
492     EXPECT_EQ(ConstString(Enum), enum_type->GetName());
493     CompilerType compiler_type = enum_type->GetFullCompilerType();
494     EXPECT_TRUE(TypeSystemClang::IsEnumType(compiler_type.GetOpaqueQualType()));
495     clang::EnumDecl *enum_decl = TypeSystemClang::GetAsEnumDecl(compiler_type);
496     EXPECT_NE(nullptr, enum_decl);
497     EXPECT_EQ(2, std::distance(enum_decl->enumerator_begin(),
498                                enum_decl->enumerator_end()));
499 
500     std::string sizeof_var = "sizeof_";
501     sizeof_var.append(Enum);
502     EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
503               enum_type->GetByteSize(nullptr));
504   }
505 }
506 
TEST_F(SymbolFilePDBTests,TestArrayTypes)507 TEST_F(SymbolFilePDBTests, TestArrayTypes) {
508   // In order to get this test working, we need to support lookup by symbol
509   // name.  Because array
510   // types themselves do not have names, only the symbols have names (i.e. the
511   // name of the array).
512 }
513 
TEST_F(SymbolFilePDBTests,TestFunctionTypes)514 TEST_F(SymbolFilePDBTests, TestFunctionTypes) {
515   // In order to get this test working, we need to support lookup by symbol
516   // name.  Because array
517   // types themselves do not have names, only the symbols have names (i.e. the
518   // name of the array).
519 }
520 
TEST_F(SymbolFilePDBTests,TestTypedefs)521 TEST_F(SymbolFilePDBTests, TestTypedefs) {
522   FileSpec fspec(m_types_test_exe);
523   ArchSpec aspec("i686-pc-windows");
524   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
525 
526   SymbolFilePDB *symfile =
527       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
528   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
529   llvm::DenseSet<SymbolFile *> searched_files;
530   TypeMap results;
531 
532   const char *TypedefsToCheck[] = {"ClassTypedef", "NSClassTypedef",
533                                    "FuncPointerTypedef",
534                                    "VariadicFuncPointerTypedef"};
535   for (auto Typedef : TypedefsToCheck) {
536     TypeMap results;
537     symfile->FindTypes(ConstString(Typedef), CompilerDeclContext(), 0,
538                        searched_files, results);
539     EXPECT_EQ(1u, results.GetSize());
540     lldb::TypeSP typedef_type = results.GetTypeAtIndex(0);
541     EXPECT_EQ(ConstString(Typedef), typedef_type->GetName());
542     CompilerType compiler_type = typedef_type->GetFullCompilerType();
543     TypeSystemClang *clang_type_system =
544         llvm::dyn_cast_or_null<TypeSystemClang>(compiler_type.GetTypeSystem());
545     EXPECT_TRUE(
546         clang_type_system->IsTypedefType(compiler_type.GetOpaqueQualType()));
547 
548     std::string sizeof_var = "sizeof_";
549     sizeof_var.append(Typedef);
550     EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
551               typedef_type->GetByteSize(nullptr));
552   }
553 }
554 
TEST_F(SymbolFilePDBTests,TestRegexNameMatch)555 TEST_F(SymbolFilePDBTests, TestRegexNameMatch) {
556   FileSpec fspec(m_types_test_exe);
557   ArchSpec aspec("i686-pc-windows");
558   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
559 
560   SymbolFilePDB *symfile =
561       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
562   TypeMap results;
563 
564   symfile->FindTypesByRegex(RegularExpression(".*"), 0, results);
565   EXPECT_GT(results.GetSize(), 1u);
566 
567   // We expect no exception thrown if the given regex can't be compiled
568   results.Clear();
569   symfile->FindTypesByRegex(RegularExpression("**"), 0, results);
570   EXPECT_EQ(0u, results.GetSize());
571 }
572 
TEST_F(SymbolFilePDBTests,TestMaxMatches)573 TEST_F(SymbolFilePDBTests, TestMaxMatches) {
574   FileSpec fspec(m_types_test_exe);
575   ArchSpec aspec("i686-pc-windows");
576   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
577 
578   SymbolFilePDB *symfile =
579       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
580   llvm::DenseSet<SymbolFile *> searched_files;
581   TypeMap results;
582   const ConstString name("ClassTypedef");
583   symfile->FindTypes(name, CompilerDeclContext(), 0, searched_files, results);
584   // Try to limit ourselves from 1 to 10 results, otherwise we could
585   // be doing this thousands of times.  The idea is just to make sure
586   // that for a variety of values, the number of limited results
587   // always comes out to the number we are expecting.
588   uint32_t num_results = results.GetSize();
589   uint32_t iterations = std::min(num_results, 10u);
590   for (uint32_t i = 1; i <= iterations; ++i) {
591     TypeMap more_results;
592     symfile->FindTypes(name, CompilerDeclContext(), i, searched_files,
593                        more_results);
594     uint32_t num_limited_results = more_results.GetSize();
595     EXPECT_EQ(i, num_limited_results);
596   }
597 }
598 
TEST_F(SymbolFilePDBTests,TestNullName)599 TEST_F(SymbolFilePDBTests, TestNullName) {
600   FileSpec fspec(m_types_test_exe);
601   ArchSpec aspec("i686-pc-windows");
602   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
603 
604   SymbolFilePDB *symfile =
605       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
606   llvm::DenseSet<SymbolFile *> searched_files;
607   TypeMap results;
608   symfile->FindTypes(ConstString(), CompilerDeclContext(), 0, searched_files,
609                      results);
610   EXPECT_EQ(0u, results.GetSize());
611 }
612 
TEST_F(SymbolFilePDBTests,TestFindSymbolsWithNameAndType)613 TEST_F(SymbolFilePDBTests, TestFindSymbolsWithNameAndType) {
614   FileSpec fspec(m_pdb_test_exe.c_str());
615   ArchSpec aspec("i686-pc-windows");
616   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
617 
618   SymbolContextList sc_list;
619   module->FindSymbolsWithNameAndType(ConstString("?foo@@YAHH@Z"),
620                                      lldb::eSymbolTypeAny, sc_list);
621   EXPECT_EQ(1u, sc_list.GetSize());
622 
623   SymbolContext sc;
624   EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
625   EXPECT_STREQ("int foo(int)",
626                sc.GetFunctionName(Mangled::ePreferDemangled).AsCString());
627 }
628