xref: /llvm-project/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp (revision 556fe5f290ea88dcbb7ced16b0f057dcebce1fd0)
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     plugin::dwarf::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     plugin::dwarf::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.GetFile()));
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=*/std::nullopt,
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=*/std::nullopt, /*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=*/std::nullopt, /*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=*/std::nullopt, /*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   TypeResults query_results;
366   symfile->FindTypes(TypeQuery("Class"), query_results);
367   TypeMap &results = query_results.GetTypeMap();
368   EXPECT_EQ(1u, results.GetSize());
369   lldb::TypeSP udt_type = results.GetTypeAtIndex(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 
TEST_F(SymbolFilePDBTests,TestNestedClassTypes)377 TEST_F(SymbolFilePDBTests, TestNestedClassTypes) {
378   FileSpec fspec(m_types_test_exe);
379   ArchSpec aspec("i686-pc-windows");
380   lldb::ModuleSP module = std::make_shared<Module>(fspec, 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(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>(clang_ast_ctx_or_err->get());
392   EXPECT_NE(nullptr, clang_ast_ctx);
393 
394   TypeResults query_results;
395   symfile->FindTypes(TypeQuery("Class"), query_results);
396   TypeMap &results = query_results.GetTypeMap();
397 
398   EXPECT_EQ(1u, results.GetSize());
399 
400   auto Class = results.GetTypeAtIndex(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(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       TypeQuery(ClassCompilerDeclCtx, ConstString("NestedClass")),
419       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(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 
TEST_F(SymbolFilePDBTests,TestClassInNamespace)433 TEST_F(SymbolFilePDBTests, TestClassInNamespace) {
434   FileSpec fspec(m_types_test_exe);
435   ArchSpec aspec("i686-pc-windows");
436   lldb::ModuleSP module = std::make_shared<Module>(fspec, 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(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>(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(ConstString("NS"), CompilerDeclContext(), true);
459   EXPECT_TRUE(ns_namespace_decl_ctx.IsValid());
460 
461   TypeResults query_results;
462   symfile->FindTypes(TypeQuery(ns_namespace_decl_ctx, ConstString("NSClass")),
463                      query_results);
464   TypeMap &results = query_results.GetTypeMap();
465   EXPECT_EQ(1u, results.GetSize());
466 
467   lldb::TypeSP udt_type = results.GetTypeAtIndex(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 
TEST_F(SymbolFilePDBTests,TestEnumTypes)477 TEST_F(SymbolFilePDBTests, TestEnumTypes) {
478   FileSpec fspec(m_types_test_exe);
479   ArchSpec aspec("i686-pc-windows");
480   lldb::ModuleSP module = std::make_shared<Module>(fspec, 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(TypeQuery(Enum), query_results);
490     TypeMap &results = query_results.GetTypeMap();
491     EXPECT_EQ(1u, results.GetSize());
492     lldb::TypeSP enum_type = results.GetTypeAtIndex(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(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(Enum);
503     EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
504               enum_type->GetByteSize(nullptr));
505   }
506 }
507 
TEST_F(SymbolFilePDBTests,TestArrayTypes)508 TEST_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 
TEST_F(SymbolFilePDBTests,TestFunctionTypes)515 TEST_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 
TEST_F(SymbolFilePDBTests,TestTypedefs)522 TEST_F(SymbolFilePDBTests, TestTypedefs) {
523   FileSpec fspec(m_types_test_exe);
524   ArchSpec aspec("i686-pc-windows");
525   lldb::ModuleSP module = std::make_shared<Module>(fspec, 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(TypeQuery(Typedef), query_results);
537     TypeMap &results = query_results.GetTypeMap();
538     EXPECT_EQ(1u, results.GetSize());
539     lldb::TypeSP typedef_type = results.GetTypeAtIndex(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(Typedef);
549     EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
550               typedef_type->GetByteSize(nullptr));
551   }
552 }
553 
TEST_F(SymbolFilePDBTests,TestRegexNameMatch)554 TEST_F(SymbolFilePDBTests, TestRegexNameMatch) {
555   FileSpec fspec(m_types_test_exe);
556   ArchSpec aspec("i686-pc-windows");
557   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
558 
559   SymbolFilePDB *symfile =
560       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
561   TypeMap results;
562 
563   symfile->FindTypesByRegex(RegularExpression(".*"), 0, 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(RegularExpression("**"), 0, results);
569   EXPECT_EQ(0u, results.GetSize());
570 }
571 
TEST_F(SymbolFilePDBTests,TestMaxMatches)572 TEST_F(SymbolFilePDBTests, TestMaxMatches) {
573   FileSpec fspec(m_types_test_exe);
574   ArchSpec aspec("i686-pc-windows");
575   lldb::ModuleSP module = std::make_shared<Module>(fspec, 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(query, 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(query, query_results);
595     TypeMap &results = query_results.GetTypeMap();
596     EXPECT_EQ(results.GetSize(), 1u);
597   }
598 }
599 
TEST_F(SymbolFilePDBTests,TestNullName)600 TEST_F(SymbolFilePDBTests, TestNullName) {
601   FileSpec fspec(m_types_test_exe);
602   ArchSpec aspec("i686-pc-windows");
603   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
604 
605   SymbolFilePDB *symfile =
606       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
607 
608   TypeResults query_results;
609   symfile->FindTypes(TypeQuery(llvm::StringRef()), query_results);
610   TypeMap &results = query_results.GetTypeMap();
611   EXPECT_EQ(0u, results.GetSize());
612 }
613 
TEST_F(SymbolFilePDBTests,TestFindSymbolsWithNameAndType)614 TEST_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>(fspec, aspec);
618 
619   SymbolContextList sc_list;
620   module->FindSymbolsWithNameAndType(ConstString("?foo@@YAHH@Z"),
621                                      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