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,
204        TestLookupOfHeaderFileWithInlines) {
205   // Test that when looking up a header file via ResolveSymbolContext (i.e. a
206   // file that was not by itself
207   // compiled, but only contributes to the combined code of other source files),
208   // a SymbolContext is returned
209   // for each compiland which has line contributions from the requested header.
210   FileSpec fspec(m_pdb_test_exe.c_str(), false);
211   ArchSpec aspec("i686-pc-windows");
212   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
213 
214   SymbolVendor *plugin = module->GetSymbolVendor();
215   EXPECT_NE(nullptr, plugin);
216   SymbolFile *symfile = plugin->GetSymbolFile();
217 
218   FileSpec header_specs[] = {FileSpec("test-pdb.h", false),
219                              FileSpec("test-pdb-nested.h", false)};
220   FileSpec main_cpp_spec("test-pdb.cpp", false);
221   FileSpec alt_cpp_spec("test-pdb-alt.cpp", false);
222   for (const auto &hspec : header_specs) {
223     SymbolContextList sc_list;
224     uint32_t result_count = symfile->ResolveSymbolContext(
225         hspec, 0, true, lldb::eSymbolContextCompUnit, sc_list);
226     EXPECT_EQ(2u, result_count);
227     EXPECT_TRUE(ContainsCompileUnit(sc_list, main_cpp_spec));
228     EXPECT_TRUE(ContainsCompileUnit(sc_list, alt_cpp_spec));
229   }
230 }
231 
232 TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithNoInlines) {
233   // Test that when looking up a header file via ResolveSymbolContext (i.e. a
234   // file that was not by itself
235   // compiled, but only contributes to the combined code of other source files),
236   // that if check_inlines
237   // is false, no SymbolContexts are returned.
238   FileSpec fspec(m_pdb_test_exe.c_str(), false);
239   ArchSpec aspec("i686-pc-windows");
240   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
241 
242   SymbolVendor *plugin = module->GetSymbolVendor();
243   EXPECT_NE(nullptr, plugin);
244   SymbolFile *symfile = plugin->GetSymbolFile();
245 
246   FileSpec header_specs[] = {FileSpec("test-pdb.h", false),
247                              FileSpec("test-pdb-nested.h", false)};
248   for (const auto &hspec : header_specs) {
249     SymbolContextList sc_list;
250     uint32_t result_count = symfile->ResolveSymbolContext(
251         hspec, 0, false, lldb::eSymbolContextCompUnit, sc_list);
252     EXPECT_EQ(0u, result_count);
253   }
254 }
255 
256 TEST_F(SymbolFilePDBTests, TestLineTablesMatchAll) {
257   // Test that when calling ResolveSymbolContext with a line number of 0, all
258   // line entries from
259   // the specified files are returned.
260   FileSpec fspec(m_pdb_test_exe.c_str(), false);
261   ArchSpec aspec("i686-pc-windows");
262   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
263 
264   SymbolVendor *plugin = module->GetSymbolVendor();
265   SymbolFile *symfile = plugin->GetSymbolFile();
266 
267   FileSpec source_file("test-pdb.cpp", false);
268   FileSpec header1("test-pdb.h", false);
269   FileSpec header2("test-pdb-nested.h", false);
270   uint32_t cus = symfile->GetNumCompileUnits();
271   EXPECT_EQ(2u, cus);
272 
273   SymbolContextList sc_list;
274   uint32_t scope = 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   uint32_t scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
324 
325   // First test with line 7, and verify that only line 7 entries are added.
326   uint32_t count =
327       symfile->ResolveSymbolContext(source_file, 7, true, scope, sc_list);
328   EXPECT_EQ(1u, count);
329   SymbolContext sc;
330   EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
331 
332   LineTable *lt = sc.comp_unit->GetLineTable();
333   EXPECT_NE(nullptr, lt);
334   count = lt->GetSize();
335   // We expect one extra entry for termination
336   EXPECT_EQ(3u, count);
337 
338   VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
339   VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
340 
341   sc_list.Clear();
342   // Then test with line 9, and verify that only line 9 entries are added.
343   count = symfile->ResolveSymbolContext(source_file, 9, true, 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 
357 TEST_F(SymbolFilePDBTests, TestSimpleClassTypes) {
358   FileSpec fspec(m_types_test_exe.c_str(), false);
359   ArchSpec aspec("i686-pc-windows");
360   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
361 
362   SymbolVendor *plugin = module->GetSymbolVendor();
363   SymbolFilePDB *symfile =
364       static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
365   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
366   SymbolContext sc;
367   llvm::DenseSet<SymbolFile *> searched_files;
368   TypeMap results;
369   EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("Class"), nullptr, false, 0,
370                                    searched_files, results));
371   EXPECT_EQ(1u, results.GetSize());
372   lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
373   EXPECT_EQ(ConstString("Class"), udt_type->GetName());
374   CompilerType compiler_type = udt_type->GetForwardCompilerType();
375   EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
376   EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_Class"),
377             udt_type->GetByteSize());
378 }
379 
380 TEST_F(SymbolFilePDBTests, TestNestedClassTypes) {
381   FileSpec fspec(m_types_test_exe.c_str(), false);
382   ArchSpec aspec("i686-pc-windows");
383   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
384 
385   SymbolVendor *plugin = module->GetSymbolVendor();
386   SymbolFilePDB *symfile =
387       static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
388   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
389   SymbolContext sc;
390   llvm::DenseSet<SymbolFile *> searched_files;
391   TypeMap results;
392 
393   auto clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
394       symfile->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
395   EXPECT_NE(nullptr, clang_ast_ctx);
396 
397   EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("Class"), nullptr, false, 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   auto ClassCompilerDeclCtx = CompilerDeclContext(clang_ast_ctx, ClassDeclCtx);
416   EXPECT_LE(1u, symfile->FindTypes(sc, ConstString("NestedClass"),
417                                    &ClassCompilerDeclCtx, false, 0,
418                                    searched_files, results));
419   EXPECT_LE(1u, results.GetSize());
420 
421   lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
422   EXPECT_EQ(ConstString("NestedClass"), udt_type->GetName());
423 
424   CompilerType compiler_type = udt_type->GetForwardCompilerType();
425   EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
426 
427   EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NestedClass"),
428             udt_type->GetByteSize());
429 }
430 
431 TEST_F(SymbolFilePDBTests, TestClassInNamespace) {
432   FileSpec fspec(m_types_test_exe.c_str(), false);
433   ArchSpec aspec("i686-pc-windows");
434   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
435 
436   SymbolVendor *plugin = module->GetSymbolVendor();
437   SymbolFilePDB *symfile =
438       static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
439   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
440   SymbolContext sc;
441   llvm::DenseSet<SymbolFile *> searched_files;
442   TypeMap results;
443 
444   auto clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
445       symfile->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
446   EXPECT_NE(nullptr, clang_ast_ctx);
447 
448   auto ast_ctx = clang_ast_ctx->getASTContext();
449   EXPECT_NE(nullptr, ast_ctx);
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 = symfile->FindNamespace(sc, ConstString("NS"), nullptr);
458   EXPECT_TRUE(ns_namespace.IsValid());
459 
460   EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("NSClass"), &ns_namespace,
461                                    false, 0, searched_files, results));
462   EXPECT_EQ(1u, results.GetSize());
463 
464   lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
465   EXPECT_EQ(ConstString("NSClass"), udt_type->GetName());
466 
467   CompilerType compiler_type = udt_type->GetForwardCompilerType();
468   EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
469 
470   EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NSClass"),
471             udt_type->GetByteSize());
472 }
473 
474 TEST_F(SymbolFilePDBTests, TestEnumTypes) {
475   FileSpec fspec(m_types_test_exe.c_str(), false);
476   ArchSpec aspec("i686-pc-windows");
477   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
478 
479   SymbolVendor *plugin = module->GetSymbolVendor();
480   SymbolFilePDB *symfile =
481       static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
482   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
483   SymbolContext sc;
484   llvm::DenseSet<SymbolFile *> searched_files;
485   const char *EnumsToCheck[] = {"Enum", "ShortEnum"};
486   for (auto Enum : EnumsToCheck) {
487     TypeMap results;
488     EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString(Enum), nullptr, false, 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(ClangASTContext::IsEnumType(compiler_type.GetOpaqueQualType()));
495     clang::EnumDecl *enum_decl = ClangASTContext::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());
504   }
505 }
506 
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 
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 
521 TEST_F(SymbolFilePDBTests, TestTypedefs) {
522   FileSpec fspec(m_types_test_exe.c_str(), false);
523   ArchSpec aspec("i686-pc-windows");
524   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
525 
526   SymbolVendor *plugin = module->GetSymbolVendor();
527   SymbolFilePDB *symfile =
528       static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
529   llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
530   SymbolContext sc;
531   llvm::DenseSet<SymbolFile *> searched_files;
532   TypeMap results;
533 
534   const char *TypedefsToCheck[] = {"ClassTypedef", "NSClassTypedef"};
535   for (auto Typedef : TypedefsToCheck) {
536     TypeMap results;
537     EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString(Typedef), nullptr, false,
538                                      0, 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     ClangASTContext *clang_type_system =
544         llvm::dyn_cast_or_null<ClangASTContext>(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());
552   }
553 }
554 
555 TEST_F(SymbolFilePDBTests, TestRegexNameMatch) {
556   FileSpec fspec(m_types_test_exe.c_str(), false);
557   ArchSpec aspec("i686-pc-windows");
558   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
559 
560   SymbolVendor *plugin = module->GetSymbolVendor();
561   SymbolFilePDB *symfile =
562       static_cast<SymbolFilePDB *>(plugin->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.c_str(), false);
576   ArchSpec aspec("i686-pc-windows");
577   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
578 
579   SymbolVendor *plugin = module->GetSymbolVendor();
580   SymbolFilePDB *symfile =
581       static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
582   SymbolContext sc;
583   llvm::DenseSet<SymbolFile *> searched_files;
584   TypeMap results;
585   const ConstString name("ClassTypedef");
586   uint32_t num_results = symfile->FindTypes(sc, name, nullptr,
587                                             false, 0, searched_files, results);
588   // Try to limit ourselves from 1 to 10 results, otherwise we could be doing
589   // this thousands of times.
590   // The idea is just to make sure that for a variety of values, the number of
591   // limited results always
592   // comes out to the number we are expecting.
593   uint32_t iterations = std::min(num_results, 10u);
594   for (uint32_t i = 1; i <= iterations; ++i) {
595     uint32_t num_limited_results = symfile->FindTypes(
596         sc, name, nullptr, false, i, searched_files, results);
597     EXPECT_EQ(i, num_limited_results);
598     EXPECT_EQ(num_limited_results, results.GetSize());
599   }
600 }
601 
602 TEST_F(SymbolFilePDBTests, TestNullName) {
603   FileSpec fspec(m_types_test_exe.c_str(), false);
604   ArchSpec aspec("i686-pc-windows");
605   lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
606 
607   SymbolVendor *plugin = module->GetSymbolVendor();
608   SymbolFilePDB *symfile =
609       static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
610   SymbolContext sc;
611   llvm::DenseSet<SymbolFile *> searched_files;
612   TypeMap results;
613   uint32_t num_results = symfile->FindTypes(sc, ConstString(), nullptr, false,
614                                             0, searched_files, results);
615   EXPECT_EQ(0u, num_results);
616   EXPECT_EQ(0u, results.GetSize());
617 }
618