text: //===-- PythonDataObjectsTests.cpp ------------------------------*- C++ -*-===//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  
  #include "gtest/gtest.h"
  
  #include "llvm/ADT/STLExtras.h"
  #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
  #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
  #include "llvm/Support/FileSystem.h"
  #include "llvm/Support/Path.h"
  #include "llvm/Testing/Support/Error.h"
  
  #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
  #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
  #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
  #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
  #include "TestingSupport/TestUtilities.h"
  #include "lldb/Core/Address.h"
  #include "lldb/Core/Module.h"
  #include "lldb/Core/ModuleSpec.h"
  #include "lldb/Host/FileSystem.h"
  #include "lldb/Host/HostInfo.h"
  #include "lldb/Symbol/CompileUnit.h"
  #include "lldb/Symbol/LineTable.h"
  #include "lldb/Symbol/TypeMap.h"
  #include "lldb/Utility/ArchSpec.h"
  #include "lldb/Utility/FileSpec.h"
  
  #if defined(_WIN32)
  #include "lldb/Host/windows/windows.h"
  #include <objbase.h>
  #endif
  
  #include <algorithm>
  
  using namespace lldb_private;
  
  class SymbolFilePDBTests : public testing::Test {
  public:
    void SetUp() override {
  // Initialize and TearDown the plugin every time, so we get a brand new
  // AST every time so that modifications to the AST from each test don't
  // leak into the next test.
  #if defined(_WIN32)
      ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
  #endif
  
      FileSystem::Initialize();
      HostInfo::Initialize();
      ObjectFilePECOFF::Initialize();
      SymbolFileDWARF::Initialize();
      TypeSystemClang::Initialize();
      SymbolFilePDB::Initialize();
  
      m_pdb_test_exe = GetInputFilePath("test-pdb.exe");
      m_types_test_exe = GetInputFilePath("test-pdb-types.exe");
    }
  
    void TearDown() override {
      SymbolFilePDB::Terminate();
      TypeSystemClang::Initialize();
      SymbolFileDWARF::Terminate();
      ObjectFilePECOFF::Terminate();
      HostInfo::Terminate();
      FileSystem::Terminate();
  
  #if defined(_WIN32)
      ::CoUninitialize();
  #endif
    }
  
  protected:
    std::string m_pdb_test_exe;
    std::string m_types_test_exe;
  
    bool FileSpecMatchesAsBaseOrFull(const FileSpec &left,
                                     const FileSpec &right) const {
      // If the filenames don't match, the paths can't be equal
      if (!left.FileEquals(right))
        return false;
      // If BOTH have a directory, also compare the directories.
      if (left.GetDirectory() && right.GetDirectory())
        return left.DirectoryEquals(right);
  
      // If one has a directory but not the other, they match.
      return true;
    }
  
    void VerifyLineEntry(lldb::ModuleSP module, const SymbolContext &sc,
                         const FileSpec &spec, LineTable &lt, uint32_t line,
                         lldb::addr_t addr) {
      LineEntry entry;
      Address address;
      EXPECT_TRUE(module->ResolveFileAddress(addr, address));
  
      EXPECT_TRUE(lt.FindLineEntryByAddress(address, entry));
      EXPECT_EQ(line, entry.line);
      EXPECT_EQ(address, entry.range.GetBaseAddress());
  
      EXPECT_TRUE(FileSpecMatchesAsBaseOrFull(spec, entry.file));
    }
  
    bool ContainsCompileUnit(const SymbolContextList &sc_list,
                             const FileSpec &spec) const {
      for (size_t i = 0; i < sc_list.GetSize(); ++i) {
        const SymbolContext &sc = sc_list[i];
        if (FileSpecMatchesAsBaseOrFull(sc.comp_unit->GetPrimaryFile(), spec))
          return true;
      }
      return false;
    }
  
    uint64_t GetGlobalConstantInteger(llvm::pdb::IPDBSession &session,
                                      llvm::StringRef var) const {
      auto global = session.getGlobalScope();
      auto results =
          global->findChildren(llvm::pdb::PDB_SymType::Data, var,
                               llvm::pdb::PDB_NameSearchFlags::NS_Default);
      uint32_t count = results->getChildCount();
      if (count == 0)
        return -1;
  
      auto item = results->getChildAtIndex(0);
      auto symbol = llvm::dyn_cast<llvm::pdb::PDBSymbolData>(item.get());
      if (!symbol)
        return -1;
      llvm::pdb::Variant value = symbol->getValue();
      switch (value.Type) {
      case llvm::pdb::PDB_VariantType::Int16:
        return value.Value.Int16;
      case llvm::pdb::PDB_VariantType::Int32:
        return value.Value.Int32;
      case llvm::pdb::PDB_VariantType::UInt16:
        return value.Value.UInt16;
      case llvm::pdb::PDB_VariantType::UInt32:
        return value.Value.UInt32;
      default:
        return 0;
      }
    }
  };
  
  TEST_F(SymbolFilePDBTests, TestAbilitiesForPDB) {
    // Test that when we have PDB debug info, SymbolFilePDB is used.
    FileSpec fspec(m_pdb_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFile *symfile = module->GetSymbolFile();
    EXPECT_NE(nullptr, symfile);
    EXPECT_EQ(symfile->GetPluginName(), SymbolFilePDB::GetPluginNameStatic());
  
    uint32_t expected_abilities = SymbolFile::kAllAbilities;
    EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
  }
  
  TEST_F(SymbolFilePDBTests, TestResolveSymbolContextBasename) {
    // Test that attempting to call ResolveSymbolContext with only a basename
    // finds all full paths
    // with the same basename
    FileSpec fspec(m_pdb_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFile *symfile = module->GetSymbolFile();
  
    FileSpec header_spec("test-pdb.cpp");
    SymbolContextList sc_list;
    uint32_t result_count = symfile->ResolveSymbolContext(
        header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list);
    EXPECT_EQ(1u, result_count);
    EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
  }
  
  TEST_F(SymbolFilePDBTests, TestResolveSymbolContextFullPath) {
    // Test that attempting to call ResolveSymbolContext with a full path only
    // finds the one source
    // file that matches the full path.
    FileSpec fspec(m_pdb_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFile *symfile = module->GetSymbolFile();
  
    FileSpec header_spec(
        R"spec(D:\src\llvm\tools\lldb\unittests\SymbolFile\PDB\Inputs\test-pdb.cpp)spec");
    SymbolContextList sc_list;
    uint32_t result_count = symfile->ResolveSymbolContext(
        header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list);
    EXPECT_GE(1u, result_count);
    EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
  }
  
  TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithInlines) {
    // Test that when looking up a header file via ResolveSymbolContext (i.e. a
    // file that was not by itself
    // compiled, but only contributes to the combined code of other source files),
    // a SymbolContext is returned
    // for each compiland which has line contributions from the requested header.
    FileSpec fspec(m_pdb_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFile *symfile = module->GetSymbolFile();
  
    FileSpec header_specs[] = {FileSpec("test-pdb.h"),
                               FileSpec("test-pdb-nested.h")};
    FileSpec main_cpp_spec("test-pdb.cpp");
    FileSpec alt_cpp_spec("test-pdb-alt.cpp");
    for (const auto &hspec : header_specs) {
      SymbolContextList sc_list;
      uint32_t result_count = symfile->ResolveSymbolContext(
          hspec, 0, true, lldb::eSymbolContextCompUnit, sc_list);
      EXPECT_EQ(2u, result_count);
      EXPECT_TRUE(ContainsCompileUnit(sc_list, main_cpp_spec));
      EXPECT_TRUE(ContainsCompileUnit(sc_list, alt_cpp_spec));
    }
  }
  
  TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithNoInlines) {
    // Test that when looking up a header file via ResolveSymbolContext (i.e. a
    // file that was not by itself
    // compiled, but only contributes to the combined code of other source files),
    // that if check_inlines
    // is false, no SymbolContexts are returned.
    FileSpec fspec(m_pdb_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFile *symfile = module->GetSymbolFile();
  
    FileSpec header_specs[] = {FileSpec("test-pdb.h"),
                               FileSpec("test-pdb-nested.h")};
    for (const auto &hspec : header_specs) {
      SymbolContextList sc_list;
      uint32_t result_count = symfile->ResolveSymbolContext(
          hspec, 0, false, lldb::eSymbolContextCompUnit, sc_list);
      EXPECT_EQ(0u, result_count);
    }
  }
  
  TEST_F(SymbolFilePDBTests, TestLineTablesMatchAll) {
    // Test that when calling ResolveSymbolContext with a line number of 0, all
    // line entries from
    // the specified files are returned.
    FileSpec fspec(m_pdb_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFile *symfile = module->GetSymbolFile();
  
    FileSpec source_file("test-pdb.cpp");
    FileSpec header1("test-pdb.h");
    FileSpec header2("test-pdb-nested.h");
    uint32_t cus = symfile->GetNumCompileUnits();
    EXPECT_EQ(2u, cus);
  
    SymbolContextList sc_list;
    lldb::SymbolContextItem scope =
        lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
  
    uint32_t count =
        symfile->ResolveSymbolContext(source_file, 0, true, scope, sc_list);
    EXPECT_EQ(1u, count);
    SymbolContext sc;
    EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
  
    LineTable *lt = sc.comp_unit->GetLineTable();
    EXPECT_NE(nullptr, lt);
    count = lt->GetSize();
    // We expect one extra entry for termination (per function)
    EXPECT_EQ(16u, count);
  
    VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
    VerifyLineEntry(module, sc, source_file, *lt, 8, 0x401043);
    VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
  
    VerifyLineEntry(module, sc, source_file, *lt, 13, 0x401050);
    VerifyLineEntry(module, sc, source_file, *lt, 14, 0x401054);
    VerifyLineEntry(module, sc, source_file, *lt, 15, 0x401070);
  
    VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
    VerifyLineEntry(module, sc, header1, *lt, 10, 0x401093);
    VerifyLineEntry(module, sc, header1, *lt, 11, 0x4010a2);
  
    VerifyLineEntry(module, sc, header2, *lt, 5, 0x401080);
    VerifyLineEntry(module, sc, header2, *lt, 6, 0x401083);
    VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
  }
  
  TEST_F(SymbolFilePDBTests, TestLineTablesMatchSpecific) {
    // Test that when calling ResolveSymbolContext with a specific line number,
    // only line entries
    // which match the requested line are returned.
    FileSpec fspec(m_pdb_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFile *symfile = module->GetSymbolFile();
  
    FileSpec source_file("test-pdb.cpp");
    FileSpec header1("test-pdb.h");
    FileSpec header2("test-pdb-nested.h");
    uint32_t cus = symfile->GetNumCompileUnits();
    EXPECT_EQ(2u, cus);
  
    SymbolContextList sc_list;
    lldb::SymbolContextItem scope =
        lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
  
    // First test with line 7, and verify that only line 7 entries are added.
    uint32_t count =
        symfile->ResolveSymbolContext(source_file, 7, true, scope, sc_list);
    EXPECT_EQ(1u, count);
    SymbolContext sc;
    EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
  
    LineTable *lt = sc.comp_unit->GetLineTable();
    EXPECT_NE(nullptr, lt);
    count = lt->GetSize();
    // We expect one extra entry for termination
    EXPECT_EQ(3u, count);
  
    VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
    VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
  
    sc_list.Clear();
    // Then test with line 9, and verify that only line 9 entries are added.
    count = symfile->ResolveSymbolContext(source_file, 9, true, scope, sc_list);
    EXPECT_EQ(1u, count);
    EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
  
    lt = sc.comp_unit->GetLineTable();
    EXPECT_NE(nullptr, lt);
    count = lt->GetSize();
    // We expect one extra entry for termination
    EXPECT_EQ(3u, count);
  
    VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
    VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
  }
  
  TEST_F(SymbolFilePDBTests, TestSimpleClassTypes) {
    FileSpec fspec(m_types_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFilePDB *symfile =
        static_cast<SymbolFilePDB *>(module->GetSymbolFile());
    llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
    llvm::DenseSet<SymbolFile *> searched_files;
    TypeMap results;
    symfile->FindTypes(ConstString("Class"), nullptr, 0, searched_files, results);
    EXPECT_EQ(1u, results.GetSize());
    lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
    EXPECT_EQ(ConstString("Class"), udt_type->GetName());
    CompilerType compiler_type = udt_type->GetForwardCompilerType();
    EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
    EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_Class"),
              udt_type->GetByteSize());
  }
  
  TEST_F(SymbolFilePDBTests, TestNestedClassTypes) {
    FileSpec fspec(m_types_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFilePDB *symfile =
        static_cast<SymbolFilePDB *>(module->GetSymbolFile());
    llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
    llvm::DenseSet<SymbolFile *> searched_files;
    TypeMap results;
  
    auto clang_ast_ctx_or_err =
        symfile->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
    ASSERT_THAT_EXPECTED(clang_ast_ctx_or_err, llvm::Succeeded());
  
    auto clang_ast_ctx =
        llvm::dyn_cast_or_null<TypeSystemClang>(&clang_ast_ctx_or_err.get());
    EXPECT_NE(nullptr, clang_ast_ctx);
  
    symfile->FindTypes(ConstString("Class"), nullptr, 0, searched_files, results);
    EXPECT_EQ(1u, results.GetSize());
  
    auto Class = results.GetTypeAtIndex(0);
    EXPECT_TRUE(Class);
    EXPECT_TRUE(Class->IsValidType());
  
    auto ClassCompilerType = Class->GetFullCompilerType();
    EXPECT_TRUE(ClassCompilerType.IsValid());
  
    auto ClassDeclCtx = clang_ast_ctx->GetDeclContextForType(ClassCompilerType);
    EXPECT_NE(nullptr, ClassDeclCtx);
  
    // There are two symbols for nested classes: one belonging to enclosing class
    // and one is global. We process correctly this case and create the same
    // compiler type for both, but `FindTypes` may return more than one type
    // (with the same compiler type) because the symbols have different IDs.
  
    TypeMap more_results;
    auto ClassCompilerDeclCtx = CompilerDeclContext(clang_ast_ctx, ClassDeclCtx);
    symfile->FindTypes(ConstString("NestedClass"), &ClassCompilerDeclCtx, 0,
                       searched_files, more_results);
    EXPECT_LE(1u, more_results.GetSize());
  
    lldb::TypeSP udt_type = more_results.GetTypeAtIndex(0);
    EXPECT_EQ(ConstString("NestedClass"), udt_type->GetName());
  
    CompilerType compiler_type = udt_type->GetForwardCompilerType();
    EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
  
    EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NestedClass"),
              udt_type->GetByteSize());
  }
  
  TEST_F(SymbolFilePDBTests, TestClassInNamespace) {
    FileSpec fspec(m_types_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFilePDB *symfile =
        static_cast<SymbolFilePDB *>(module->GetSymbolFile());
    llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
    llvm::DenseSet<SymbolFile *> searched_files;
    TypeMap results;
  
    auto clang_ast_ctx_or_err =
        symfile->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
    ASSERT_THAT_EXPECTED(clang_ast_ctx_or_err, llvm::Succeeded());
  
    auto clang_ast_ctx =
        llvm::dyn_cast_or_null<TypeSystemClang>(&clang_ast_ctx_or_err.get());
    EXPECT_NE(nullptr, clang_ast_ctx);
  
    clang::ASTContext &ast_ctx = clang_ast_ctx->getASTContext();
  
    auto tu = ast_ctx.getTranslationUnitDecl();
    EXPECT_NE(nullptr, tu);
  
    symfile->ParseDeclsForContext(CompilerDeclContext(
        clang_ast_ctx, static_cast<clang::DeclContext *>(tu)));
  
    auto ns_namespace = symfile->FindNamespace(ConstString("NS"), nullptr);
    EXPECT_TRUE(ns_namespace.IsValid());
  
    symfile->FindTypes(ConstString("NSClass"), &ns_namespace, 0, searched_files,
                       results);
    EXPECT_EQ(1u, results.GetSize());
  
    lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
    EXPECT_EQ(ConstString("NSClass"), udt_type->GetName());
  
    CompilerType compiler_type = udt_type->GetForwardCompilerType();
    EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
  
    EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NSClass"),
              udt_type->GetByteSize());
  }
  
  TEST_F(SymbolFilePDBTests, TestEnumTypes) {
    FileSpec fspec(m_types_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFilePDB *symfile =
        static_cast<SymbolFilePDB *>(module->GetSymbolFile());
    llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
    llvm::DenseSet<SymbolFile *> searched_files;
    const char *EnumsToCheck[] = {"Enum", "ShortEnum"};
    for (auto Enum : EnumsToCheck) {
      TypeMap results;
      symfile->FindTypes(ConstString(Enum), nullptr, 0, searched_files, results);
      EXPECT_EQ(1u, results.GetSize());
      lldb::TypeSP enum_type = results.GetTypeAtIndex(0);
      EXPECT_EQ(ConstString(Enum), enum_type->GetName());
      CompilerType compiler_type = enum_type->GetFullCompilerType();
      EXPECT_TRUE(TypeSystemClang::IsEnumType(compiler_type.GetOpaqueQualType()));
      clang::EnumDecl *enum_decl = TypeSystemClang::GetAsEnumDecl(compiler_type);
      EXPECT_NE(nullptr, enum_decl);
      EXPECT_EQ(2, std::distance(enum_decl->enumerator_begin(),
                                 enum_decl->enumerator_end()));
  
      std::string sizeof_var = "sizeof_";
      sizeof_var.append(Enum);
      EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
                enum_type->GetByteSize());
    }
  }
  
  TEST_F(SymbolFilePDBTests, TestArrayTypes) {
    // In order to get this test working, we need to support lookup by symbol
    // name.  Because array
    // types themselves do not have names, only the symbols have names (i.e. the
    // name of the array).
  }
  
  TEST_F(SymbolFilePDBTests, TestFunctionTypes) {
    // In order to get this test working, we need to support lookup by symbol
    // name.  Because array
    // types themselves do not have names, only the symbols have names (i.e. the
    // name of the array).
  }
  
  TEST_F(SymbolFilePDBTests, TestTypedefs) {
    FileSpec fspec(m_types_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFilePDB *symfile =
        static_cast<SymbolFilePDB *>(module->GetSymbolFile());
    llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
    llvm::DenseSet<SymbolFile *> searched_files;
    TypeMap results;
  
    const char *TypedefsToCheck[] = {"ClassTypedef", "NSClassTypedef",
                                     "FuncPointerTypedef",
                                     "VariadicFuncPointerTypedef"};
    for (auto Typedef : TypedefsToCheck) {
      TypeMap results;
      symfile->FindTypes(ConstString(Typedef), nullptr, 0, searched_files,
                         results);
      EXPECT_EQ(1u, results.GetSize());
      lldb::TypeSP typedef_type = results.GetTypeAtIndex(0);
      EXPECT_EQ(ConstString(Typedef), typedef_type->GetName());
      CompilerType compiler_type = typedef_type->GetFullCompilerType();
      TypeSystemClang *clang_type_system =
          llvm::dyn_cast_or_null<TypeSystemClang>(compiler_type.GetTypeSystem());
      EXPECT_TRUE(
          clang_type_system->IsTypedefType(compiler_type.GetOpaqueQualType()));
  
      std::string sizeof_var = "sizeof_";
      sizeof_var.append(Typedef);
      EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
                typedef_type->GetByteSize());
    }
  }
  
  TEST_F(SymbolFilePDBTests, TestRegexNameMatch) {
    FileSpec fspec(m_types_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFilePDB *symfile =
        static_cast<SymbolFilePDB *>(module->GetSymbolFile());
    TypeMap results;
  
    symfile->FindTypesByRegex(RegularExpression(".*"), 0, results);
    EXPECT_GT(results.GetSize(), 1u);
  
    // We expect no exception thrown if the given regex can't be compiled
    results.Clear();
    symfile->FindTypesByRegex(RegularExpression("**"), 0, results);
    EXPECT_EQ(0u, results.GetSize());
  }
  
  TEST_F(SymbolFilePDBTests, TestMaxMatches) {
    FileSpec fspec(m_types_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFilePDB *symfile =
        static_cast<SymbolFilePDB *>(module->GetSymbolFile());
    llvm::DenseSet<SymbolFile *> searched_files;
    TypeMap results;
    const ConstString name("ClassTypedef");
    symfile->FindTypes(name, nullptr, 0, searched_files, results);
    // Try to limit ourselves from 1 to 10 results, otherwise we could
    // be doing this thousands of times.  The idea is just to make sure
    // that for a variety of values, the number of limited results
    // always comes out to the number we are expecting.
    uint32_t num_results = results.GetSize();
    uint32_t iterations = std::min(num_results, 10u);
    for (uint32_t i = 1; i <= iterations; ++i) {
      TypeMap more_results;
      symfile->FindTypes(name, nullptr, i, searched_files, more_results);
      uint32_t num_limited_results = more_results.GetSize();
      EXPECT_EQ(i, num_limited_results);
    }
  }
  
  TEST_F(SymbolFilePDBTests, TestNullName) {
    FileSpec fspec(m_types_test_exe);
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolFilePDB *symfile =
        static_cast<SymbolFilePDB *>(module->GetSymbolFile());
    llvm::DenseSet<SymbolFile *> searched_files;
    TypeMap results;
    symfile->FindTypes(ConstString(), nullptr, 0, searched_files, results);
    EXPECT_EQ(0u, results.GetSize());
  }
  
  TEST_F(SymbolFilePDBTests, TestFindSymbolsWithNameAndType) {
    FileSpec fspec(m_pdb_test_exe.c_str());
    ArchSpec aspec("i686-pc-windows");
    lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
  
    SymbolContextList sc_list;
    module->FindSymbolsWithNameAndType(ConstString("?foo@@YAHH@Z"),
                                       lldb::eSymbolTypeAny, sc_list);
    EXPECT_EQ(1u, sc_list.GetSize());
  
    SymbolContext sc;
    EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
    EXPECT_STREQ("int foo(int)",
                 sc.GetFunctionName(Mangled::ePreferDemangled).AsCString());
  }
  