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:
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 
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 
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(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 
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 
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(sc.comp_unit->GetPrimaryFile(), 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(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 
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(),
157             SymbolFilePDB::GetPluginNameStatic().GetStringRef());
158 
159   uint32_t expected_abilities = SymbolFile::kAllAbilities;
160   EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
161 }
162 
163 TEST_F(SymbolFilePDBTests, TestResolveSymbolContextBasename) {
164   // Test that attempting to call ResolveSymbolContext with only a basename
165   // finds all full paths
166   // with the same basename
167   FileSpec fspec(m_pdb_test_exe);
168   ArchSpec aspec("i686-pc-windows");
169   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
170 
171   SymbolFile *symfile = module->GetSymbolFile();
172 
173   FileSpec header_spec("test-pdb.cpp");
174   SymbolContextList sc_list;
175   SourceLocationSpec location_spec(header_spec, /*line=*/0);
176   uint32_t result_count = symfile->ResolveSymbolContext(
177       location_spec, lldb::eSymbolContextCompUnit, sc_list);
178   EXPECT_EQ(1u, result_count);
179   EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
180 }
181 
182 TEST_F(SymbolFilePDBTests, TestResolveSymbolContextFullPath) {
183   // Test that attempting to call ResolveSymbolContext with a full path only
184   // finds the one source
185   // file that matches the full path.
186   FileSpec fspec(m_pdb_test_exe);
187   ArchSpec aspec("i686-pc-windows");
188   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
189 
190   SymbolFile *symfile = module->GetSymbolFile();
191 
192   FileSpec header_spec(
193       R"spec(D:\src\llvm\tools\lldb\unittests\SymbolFile\PDB\Inputs\test-pdb.cpp)spec");
194   SymbolContextList sc_list;
195   SourceLocationSpec location_spec(header_spec, /*line=*/0);
196   uint32_t result_count = symfile->ResolveSymbolContext(
197       location_spec, lldb::eSymbolContextCompUnit, sc_list);
198   EXPECT_GE(1u, result_count);
199   EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
200 }
201 
202 TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithInlines) {
203   // Test that when looking up a header file via ResolveSymbolContext (i.e. a
204   // file that was not by itself
205   // compiled, but only contributes to the combined code of other source files),
206   // a SymbolContext is returned
207   // for each compiland which has line contributions from the requested header.
208   FileSpec fspec(m_pdb_test_exe);
209   ArchSpec aspec("i686-pc-windows");
210   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
211 
212   SymbolFile *symfile = module->GetSymbolFile();
213 
214   FileSpec header_specs[] = {FileSpec("test-pdb.h"),
215                              FileSpec("test-pdb-nested.h")};
216   FileSpec main_cpp_spec("test-pdb.cpp");
217   FileSpec alt_cpp_spec("test-pdb-alt.cpp");
218   for (const auto &hspec : header_specs) {
219     SymbolContextList sc_list;
220     SourceLocationSpec location_spec(hspec, /*line=*/0, /*column=*/llvm::None,
221                                      /*check_inlines=*/true);
222     uint32_t result_count = symfile->ResolveSymbolContext(
223         location_spec, lldb::eSymbolContextCompUnit, sc_list);
224     EXPECT_EQ(2u, result_count);
225     EXPECT_TRUE(ContainsCompileUnit(sc_list, main_cpp_spec));
226     EXPECT_TRUE(ContainsCompileUnit(sc_list, alt_cpp_spec));
227   }
228 }
229 
230 TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithNoInlines) {
231   // Test that when looking up a header file via ResolveSymbolContext (i.e. a
232   // file that was not by itself
233   // compiled, but only contributes to the combined code of other source files),
234   // that if check_inlines
235   // is false, no SymbolContexts are returned.
236   FileSpec fspec(m_pdb_test_exe);
237   ArchSpec aspec("i686-pc-windows");
238   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
239 
240   SymbolFile *symfile = module->GetSymbolFile();
241 
242   FileSpec header_specs[] = {FileSpec("test-pdb.h"),
243                              FileSpec("test-pdb-nested.h")};
244   for (const auto &hspec : header_specs) {
245     SymbolContextList sc_list;
246     SourceLocationSpec location_spec(hspec, /*line=*/0);
247     uint32_t result_count = symfile->ResolveSymbolContext(
248         location_spec, lldb::eSymbolContextCompUnit, sc_list);
249     EXPECT_EQ(0u, result_count);
250   }
251 }
252 
253 TEST_F(SymbolFilePDBTests, TestLineTablesMatchAll) {
254   // Test that when calling ResolveSymbolContext with a line number of 0, all
255   // line entries from
256   // the specified files are returned.
257   FileSpec fspec(m_pdb_test_exe);
258   ArchSpec aspec("i686-pc-windows");
259   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
260 
261   SymbolFile *symfile = module->GetSymbolFile();
262 
263   FileSpec source_file("test-pdb.cpp");
264   FileSpec header1("test-pdb.h");
265   FileSpec header2("test-pdb-nested.h");
266   uint32_t cus = symfile->GetNumCompileUnits();
267   EXPECT_EQ(2u, cus);
268 
269   SymbolContextList sc_list;
270   lldb::SymbolContextItem scope =
271       lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
272 
273   SourceLocationSpec location_spec(
274       source_file, /*line=*/0, /*column=*/llvm::None, /*check_inlines=*/true);
275   uint32_t count = symfile->ResolveSymbolContext(location_spec, scope, sc_list);
276   EXPECT_EQ(1u, count);
277   SymbolContext sc;
278   EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
279 
280   LineTable *lt = sc.comp_unit->GetLineTable();
281   EXPECT_NE(nullptr, lt);
282   count = lt->GetSize();
283   // We expect one extra entry for termination (per function)
284   EXPECT_EQ(16u, count);
285 
286   VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
287   VerifyLineEntry(module, sc, source_file, *lt, 8, 0x401043);
288   VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
289 
290   VerifyLineEntry(module, sc, source_file, *lt, 13, 0x401050);
291   VerifyLineEntry(module, sc, source_file, *lt, 14, 0x401054);
292   VerifyLineEntry(module, sc, source_file, *lt, 15, 0x401070);
293 
294   VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
295   VerifyLineEntry(module, sc, header1, *lt, 10, 0x401093);
296   VerifyLineEntry(module, sc, header1, *lt, 11, 0x4010a2);
297 
298   VerifyLineEntry(module, sc, header2, *lt, 5, 0x401080);
299   VerifyLineEntry(module, sc, header2, *lt, 6, 0x401083);
300   VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
301 }
302 
303 TEST_F(SymbolFilePDBTests, TestLineTablesMatchSpecific) {
304   // Test that when calling ResolveSymbolContext with a specific line number,
305   // only line entries
306   // which match the requested line are returned.
307   FileSpec fspec(m_pdb_test_exe);
308   ArchSpec aspec("i686-pc-windows");
309   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
310 
311   SymbolFile *symfile = module->GetSymbolFile();
312 
313   FileSpec source_file("test-pdb.cpp");
314   FileSpec header1("test-pdb.h");
315   FileSpec header2("test-pdb-nested.h");
316   uint32_t cus = symfile->GetNumCompileUnits();
317   EXPECT_EQ(2u, cus);
318 
319   SymbolContextList sc_list;
320   lldb::SymbolContextItem scope =
321       lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
322 
323   // First test with line 7, and verify that only line 7 entries are added.
324   SourceLocationSpec location_spec(
325       source_file, /*line=*/7, /*column=*/llvm::None, /*check_inlines=*/true);
326   uint32_t count = symfile->ResolveSymbolContext(location_spec, scope, sc_list);
327   EXPECT_EQ(1u, count);
328   SymbolContext sc;
329   EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
330 
331   LineTable *lt = sc.comp_unit->GetLineTable();
332   EXPECT_NE(nullptr, lt);
333   count = lt->GetSize();
334   // We expect one extra entry for termination
335   EXPECT_EQ(3u, count);
336 
337   VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
338   VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
339 
340   sc_list.Clear();
341   // Then test with line 9, and verify that only line 9 entries are added.
342   location_spec = SourceLocationSpec(
343       source_file, /*line=*/9, /*column=*/llvm::None, /*check_inlines=*/true);
344   count = symfile->ResolveSymbolContext(location_spec, scope, sc_list);
345   EXPECT_EQ(1u, count);
346   EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
347 
348   lt = sc.comp_unit->GetLineTable();
349   EXPECT_NE(nullptr, lt);
350   count = lt->GetSize();
351   // We expect one extra entry for termination
352   EXPECT_EQ(3u, count);
353 
354   VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
355   VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
356 }
357 
358 TEST_F(SymbolFilePDBTests, TestSimpleClassTypes) {
359   FileSpec fspec(m_types_test_exe);
360   ArchSpec aspec("i686-pc-windows");
361   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
362 
363   SymbolFilePDB *symfile =
364       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
365   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
366   llvm::DenseSet<SymbolFile *> searched_files;
367   TypeMap results;
368   symfile->FindTypes(ConstString("Class"), CompilerDeclContext(), 0,
369                      searched_files, results);
370   EXPECT_EQ(1u, results.GetSize());
371   lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
372   EXPECT_EQ(ConstString("Class"), udt_type->GetName());
373   CompilerType compiler_type = udt_type->GetForwardCompilerType();
374   EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
375   EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_Class"),
376             udt_type->GetByteSize(nullptr));
377 }
378 
379 TEST_F(SymbolFilePDBTests, TestNestedClassTypes) {
380   FileSpec fspec(m_types_test_exe);
381   ArchSpec aspec("i686-pc-windows");
382   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
383 
384   SymbolFilePDB *symfile =
385       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
386   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
387   llvm::DenseSet<SymbolFile *> searched_files;
388   TypeMap results;
389 
390   auto clang_ast_ctx_or_err =
391       symfile->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
392   ASSERT_THAT_EXPECTED(clang_ast_ctx_or_err, llvm::Succeeded());
393 
394   auto clang_ast_ctx =
395       llvm::dyn_cast_or_null<TypeSystemClang>(&clang_ast_ctx_or_err.get());
396   EXPECT_NE(nullptr, clang_ast_ctx);
397 
398   symfile->FindTypes(ConstString("Class"), CompilerDeclContext(), 0,
399                      searched_files, results);
400   EXPECT_EQ(1u, results.GetSize());
401 
402   auto Class = results.GetTypeAtIndex(0);
403   EXPECT_TRUE(Class);
404   EXPECT_TRUE(Class->IsValidType());
405 
406   auto ClassCompilerType = Class->GetFullCompilerType();
407   EXPECT_TRUE(ClassCompilerType.IsValid());
408 
409   auto ClassDeclCtx = clang_ast_ctx->GetDeclContextForType(ClassCompilerType);
410   EXPECT_NE(nullptr, ClassDeclCtx);
411 
412   // There are two symbols for nested classes: one belonging to enclosing class
413   // and one is global. We process correctly this case and create the same
414   // compiler type for both, but `FindTypes` may return more than one type
415   // (with the same compiler type) because the symbols have different IDs.
416 
417   TypeMap more_results;
418   auto ClassCompilerDeclCtx = CompilerDeclContext(clang_ast_ctx, ClassDeclCtx);
419   symfile->FindTypes(ConstString("NestedClass"), ClassCompilerDeclCtx, 0,
420                      searched_files, more_results);
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 
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   llvm::DenseSet<SymbolFile *> searched_files;
442   TypeMap results;
443 
444   auto clang_ast_ctx_or_err =
445       symfile->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
446   ASSERT_THAT_EXPECTED(clang_ast_ctx_or_err, llvm::Succeeded());
447 
448   auto clang_ast_ctx =
449       llvm::dyn_cast_or_null<TypeSystemClang>(&clang_ast_ctx_or_err.get());
450   EXPECT_NE(nullptr, clang_ast_ctx);
451 
452   clang::ASTContext &ast_ctx = clang_ast_ctx->getASTContext();
453 
454   auto tu = ast_ctx.getTranslationUnitDecl();
455   EXPECT_NE(nullptr, tu);
456 
457   symfile->ParseDeclsForContext(CompilerDeclContext(
458       clang_ast_ctx, static_cast<clang::DeclContext *>(tu)));
459 
460   auto ns_namespace = symfile->FindNamespace(ConstString("NS"), CompilerDeclContext());
461   EXPECT_TRUE(ns_namespace.IsValid());
462 
463   symfile->FindTypes(ConstString("NSClass"), ns_namespace, 0, searched_files,
464                      results);
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 
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   llvm::DenseSet<SymbolFile *> searched_files;
486   const char *EnumsToCheck[] = {"Enum", "ShortEnum"};
487   for (auto Enum : EnumsToCheck) {
488     TypeMap results;
489     symfile->FindTypes(ConstString(Enum), CompilerDeclContext(), 0,
490                        searched_files, results);
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 
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 
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 
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   llvm::DenseSet<SymbolFile *> searched_files;
531   TypeMap results;
532 
533   const char *TypedefsToCheck[] = {"ClassTypedef", "NSClassTypedef",
534                                    "FuncPointerTypedef",
535                                    "VariadicFuncPointerTypedef"};
536   for (auto Typedef : TypedefsToCheck) {
537     TypeMap results;
538     symfile->FindTypes(ConstString(Typedef), CompilerDeclContext(), 0,
539                        searched_files, results);
540     EXPECT_EQ(1u, results.GetSize());
541     lldb::TypeSP typedef_type = results.GetTypeAtIndex(0);
542     EXPECT_EQ(ConstString(Typedef), typedef_type->GetName());
543     CompilerType compiler_type = typedef_type->GetFullCompilerType();
544     TypeSystemClang *clang_type_system =
545         llvm::dyn_cast_or_null<TypeSystemClang>(compiler_type.GetTypeSystem());
546     EXPECT_TRUE(
547         clang_type_system->IsTypedefType(compiler_type.GetOpaqueQualType()));
548 
549     std::string sizeof_var = "sizeof_";
550     sizeof_var.append(Typedef);
551     EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
552               typedef_type->GetByteSize(nullptr));
553   }
554 }
555 
556 TEST_F(SymbolFilePDBTests, TestRegexNameMatch) {
557   FileSpec fspec(m_types_test_exe);
558   ArchSpec aspec("i686-pc-windows");
559   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
560 
561   SymbolFilePDB *symfile =
562       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
563   TypeMap results;
564 
565   symfile->FindTypesByRegex(RegularExpression(".*"), 0, results);
566   EXPECT_GT(results.GetSize(), 1u);
567 
568   // We expect no exception thrown if the given regex can't be compiled
569   results.Clear();
570   symfile->FindTypesByRegex(RegularExpression("**"), 0, results);
571   EXPECT_EQ(0u, results.GetSize());
572 }
573 
574 TEST_F(SymbolFilePDBTests, TestMaxMatches) {
575   FileSpec fspec(m_types_test_exe);
576   ArchSpec aspec("i686-pc-windows");
577   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
578 
579   SymbolFilePDB *symfile =
580       static_cast<SymbolFilePDB *>(module->GetSymbolFile());
581   llvm::DenseSet<SymbolFile *> searched_files;
582   TypeMap results;
583   const ConstString name("ClassTypedef");
584   symfile->FindTypes(name, CompilerDeclContext(), 0, searched_files, results);
585   // Try to limit ourselves from 1 to 10 results, otherwise we could
586   // be doing this thousands of times.  The idea is just to make sure
587   // that for a variety of values, the number of limited results
588   // always comes out to the number we are expecting.
589   uint32_t num_results = results.GetSize();
590   uint32_t iterations = std::min(num_results, 10u);
591   for (uint32_t i = 1; i <= iterations; ++i) {
592     TypeMap more_results;
593     symfile->FindTypes(name, CompilerDeclContext(), i, searched_files,
594                        more_results);
595     uint32_t num_limited_results = more_results.GetSize();
596     EXPECT_EQ(i, num_limited_results);
597   }
598 }
599 
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   llvm::DenseSet<SymbolFile *> searched_files;
608   TypeMap results;
609   symfile->FindTypes(ConstString(), CompilerDeclContext(), 0, searched_files,
610                      results);
611   EXPECT_EQ(0u, results.GetSize());
612 }
613 
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