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