summaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
Diffstat (limited to 'unittests')
-rw-r--r--unittests/CMakeLists.txt18
-rw-r--r--unittests/Core/CMakeLists.txt4
-rw-r--r--unittests/Core/DataExtractorTest.cpp39
-rw-r--r--unittests/Core/ScalarTest.cpp105
-rw-r--r--unittests/Editline/EditlineTest.cpp74
-rw-r--r--unittests/Host/CMakeLists.txt1
-rw-r--r--unittests/Host/FileSpecTest.cpp111
-rw-r--r--unittests/Host/SocketAddressTest.cpp7
-rw-r--r--unittests/Host/SocketTest.cpp12
-rw-r--r--unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp54
-rw-r--r--unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp2
-rw-r--r--unittests/ScriptInterpreter/Python/PythonTestSuite.cpp1
-rw-r--r--unittests/Symbol/CMakeLists.txt3
-rw-r--r--unittests/Symbol/TestClangASTContext.cpp315
-rw-r--r--unittests/SymbolFile/CMakeLists.txt1
-rw-r--r--unittests/SymbolFile/PDB/CMakeLists.txt12
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-dwarf.cpp14
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-dwarf.exebin0 -> 6144 bytes
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb-alt.cpp9
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb-nested.h9
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp86
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb-types.exebin0 -> 7168 bytes
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb-types.pdbbin0 -> 143360 bytes
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb.cpp15
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb.exebin0 -> 7168 bytes
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb.h13
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb.pdbbin0 -> 110592 bytes
-rw-r--r--unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp583
-rw-r--r--unittests/Utility/CMakeLists.txt3
-rw-r--r--unittests/Utility/Inputs/TestModule.c10
-rw-r--r--unittests/Utility/Inputs/TestModule.sobin0 -> 5602 bytes
-rw-r--r--unittests/Utility/ModuleCacheTest.cpp179
32 files changed, 1617 insertions, 63 deletions
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 94031accfec77..bdcb51675a0f8 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -18,14 +18,32 @@ function(add_lldb_unittest test_name)
${ARGN}
)
+ add_custom_command(
+ TARGET ${test_name}
+ POST_BUILD
+ COMMAND "${CMAKE_COMMAND}" -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/Inputs)
+
lldb_link_common_libs(${test_name} EXE)
target_link_libraries(${test_name} ${CLANG_USED_LIBS} ${LLDB_SYSTEM_LIBS})
llvm_config(${test_name} ${LLVM_LINK_COMPONENTS})
endfunction()
+function(add_unittest_inputs test_name inputs)
+ foreach (INPUT ${inputs})
+ add_custom_command(
+ TARGET ${test_name}
+ POST_BUILD
+ COMMAND "${CMAKE_COMMAND}" -E copy ${CMAKE_CURRENT_SOURCE_DIR}/Inputs/${INPUT} ${CMAKE_CURRENT_BINARY_DIR}/Inputs
+ COMMENT "Copying ${INPUT} to binary directory.")
+ endforeach()
+endfunction()
+
+add_subdirectory(Core)
add_subdirectory(Editline)
add_subdirectory(Expression)
add_subdirectory(Host)
add_subdirectory(Interpreter)
add_subdirectory(ScriptInterpreter)
+add_subdirectory(Symbol)
+add_subdirectory(SymbolFile)
add_subdirectory(Utility)
diff --git a/unittests/Core/CMakeLists.txt b/unittests/Core/CMakeLists.txt
new file mode 100644
index 0000000000000..ad9def181de58
--- /dev/null
+++ b/unittests/Core/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_lldb_unittest(LLDBCoreTests
+ DataExtractorTest.cpp
+ ScalarTest.cpp
+ )
diff --git a/unittests/Core/DataExtractorTest.cpp b/unittests/Core/DataExtractorTest.cpp
new file mode 100644
index 0000000000000..f22883875055f
--- /dev/null
+++ b/unittests/Core/DataExtractorTest.cpp
@@ -0,0 +1,39 @@
+//===-- DataExtractorTest.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
+// Workaround for MSVC standard library bug, which fails to include <thread> when
+// exceptions are disabled.
+#include <eh.h>
+#endif
+
+#include "gtest/gtest.h"
+
+#include "lldb/Core/DataExtractor.h"
+
+using namespace lldb_private;
+
+TEST(DataExtractorTest, GetBitfield)
+{
+ char buffer[] = { 0x01, 0x23, 0x45, 0x67 };
+ DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, sizeof(void *));
+ DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
+
+ lldb::offset_t offset;
+
+ offset = 0;
+ ASSERT_EQ(buffer[1], LE.GetMaxU64Bitfield(&offset, sizeof(buffer), 8, 8));
+ offset = 0;
+ ASSERT_EQ(buffer[1], BE.GetMaxU64Bitfield(&offset, sizeof(buffer), 8, 8));
+
+ offset = 0;
+ ASSERT_EQ(buffer[1], LE.GetMaxS64Bitfield(&offset, sizeof(buffer), 8, 8));
+ offset = 0;
+ ASSERT_EQ(buffer[1], BE.GetMaxS64Bitfield(&offset, sizeof(buffer), 8, 8));
+}
diff --git a/unittests/Core/ScalarTest.cpp b/unittests/Core/ScalarTest.cpp
new file mode 100644
index 0000000000000..bf85f8e9623b0
--- /dev/null
+++ b/unittests/Core/ScalarTest.cpp
@@ -0,0 +1,105 @@
+//===-- ScalarTest.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
+// Workaround for MSVC standard library bug, which fails to include <thread> when
+// exceptions are disabled.
+#include <eh.h>
+#endif
+
+#include "gtest/gtest.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Host/Endian.h"
+
+using namespace lldb_private;
+
+TEST(ScalarTest, RightShiftOperator)
+{
+ int a = 0x00001000;
+ int b = 0xFFFFFFFF;
+ int c = 4;
+ Scalar a_scalar(a);
+ Scalar b_scalar(b);
+ Scalar c_scalar(c);
+ ASSERT_EQ(a >> c, a_scalar >> c_scalar);
+ ASSERT_EQ(b >> c, b_scalar >> c_scalar);
+}
+
+TEST(ScalarTest, GetBytes)
+{
+ int a = 0x01020304;
+ long long b = 0x0102030405060708LL;
+ float c = 1234567.89e42;
+ double d = 1234567.89e42;
+ char e[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+ char f[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
+ Scalar a_scalar(a);
+ Scalar b_scalar(b);
+ Scalar c_scalar(c);
+ Scalar d_scalar(d);
+ Scalar e_scalar;
+ Scalar f_scalar;
+ DataExtractor e_data(e, sizeof(e), endian::InlHostByteOrder(), sizeof(void *));
+ Error e_error = e_scalar.SetValueFromData(e_data, lldb::eEncodingUint, sizeof(e));
+ DataExtractor f_data(f, sizeof(f), endian::InlHostByteOrder(), sizeof(void *));
+ Error f_error = f_scalar.SetValueFromData(f_data, lldb::eEncodingUint, sizeof(f));
+ ASSERT_EQ(0, memcmp(&a, a_scalar.GetBytes(), sizeof(a)));
+ ASSERT_EQ(0, memcmp(&b, b_scalar.GetBytes(), sizeof(b)));
+ ASSERT_EQ(0, memcmp(&c, c_scalar.GetBytes(), sizeof(c)));
+ ASSERT_EQ(0, memcmp(&d, d_scalar.GetBytes(), sizeof(d)));
+ ASSERT_EQ(0, e_error.Fail());
+ ASSERT_EQ(0, memcmp(e, e_scalar.GetBytes(), sizeof(e)));
+ ASSERT_EQ(0, f_error.Fail());
+ ASSERT_EQ(0, memcmp(f, f_scalar.GetBytes(), sizeof(f)));
+}
+
+TEST(ScalarTest, CastOperations)
+{
+ long long a = 0xf1f2f3f4f5f6f7f8LL;
+ Scalar a_scalar(a);
+ ASSERT_EQ((signed char)a, a_scalar.SChar());
+ ASSERT_EQ((unsigned char)a, a_scalar.UChar());
+ ASSERT_EQ((signed short)a, a_scalar.SShort());
+ ASSERT_EQ((unsigned short)a, a_scalar.UShort());
+ ASSERT_EQ((signed int)a, a_scalar.SInt());
+ ASSERT_EQ((unsigned int)a, a_scalar.UInt());
+ ASSERT_EQ((signed long)a, a_scalar.SLong());
+ ASSERT_EQ((unsigned long)a, a_scalar.ULong());
+ ASSERT_EQ((signed long long)a, a_scalar.SLongLong());
+ ASSERT_EQ((unsigned long long)a, a_scalar.ULongLong());
+}
+
+TEST(ScalarTest, ExtractBitfield)
+{
+ uint32_t len = sizeof(long long) * 8;
+
+ long long a1 = 0xf1f2f3f4f5f6f7f8LL;
+ long long b1 = 0xff1f2f3f4f5f6f7fLL;
+ Scalar s_scalar(a1);
+ ASSERT_TRUE(s_scalar.ExtractBitfield(0, 0));
+ ASSERT_EQ(0, memcmp(&a1, s_scalar.GetBytes(), sizeof(a1)));
+ ASSERT_TRUE(s_scalar.ExtractBitfield(len, 0));
+ ASSERT_EQ(0, memcmp(&a1, s_scalar.GetBytes(), sizeof(a1)));
+ ASSERT_TRUE(s_scalar.ExtractBitfield(len - 4, 4));
+ ASSERT_EQ(0, memcmp(&b1, s_scalar.GetBytes(), sizeof(b1)));
+
+ unsigned long long a2 = 0xf1f2f3f4f5f6f7f8ULL;
+ unsigned long long b2 = 0x0f1f2f3f4f5f6f7fULL;
+ Scalar u_scalar(a2);
+ ASSERT_TRUE(u_scalar.ExtractBitfield(0, 0));
+ ASSERT_EQ(0, memcmp(&a2, u_scalar.GetBytes(), sizeof(a2)));
+ ASSERT_TRUE(u_scalar.ExtractBitfield(len, 0));
+ ASSERT_EQ(0, memcmp(&a2, u_scalar.GetBytes(), sizeof(a2)));
+ ASSERT_TRUE(u_scalar.ExtractBitfield(len - 4, 4));
+ ASSERT_EQ(0, memcmp(&b2, u_scalar.GetBytes(), sizeof(b2)));
+}
diff --git a/unittests/Editline/EditlineTest.cpp b/unittests/Editline/EditlineTest.cpp
index d82ef4c17c773..e2552ffdd3b83 100644
--- a/unittests/Editline/EditlineTest.cpp
+++ b/unittests/Editline/EditlineTest.cpp
@@ -1,4 +1,4 @@
-//===-- EditlineTest.cpp -----------------------------------------*- C++ -*-===//
+//===-- EditlineTest.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -191,8 +191,9 @@ EditlineAdapter::SendLine (const std::string &line)
eoln,
eoln_length * sizeof (char));
- EXPECT_EQ (eoln_length * sizeof (char), input_bytes_written);
- return eoln_length * sizeof (char) == input_bytes_written;
+ EXPECT_NE(-1, input_bytes_written) << strerror(errno);
+ EXPECT_EQ (eoln_length * sizeof (char), size_t(input_bytes_written));
+ return eoln_length * sizeof (char) == size_t(input_bytes_written);
}
bool
@@ -293,49 +294,55 @@ EditlineAdapter::ConsumeAllOutput ()
}
}
-TEST (EditlineTest, EditlineReceivesSingleLineText)
+class EditlineTestFixture : public ::testing::Test
{
- setenv ("TERM", "vt100", 1);
+private:
+ EditlineAdapter _el_adapter;
+ std::shared_ptr<std::thread> _sp_output_thread;
- // Create an editline.
- EditlineAdapter el_adapter;
- EXPECT_TRUE (el_adapter.IsValid ());
- if (!el_adapter.IsValid ())
- return;
+public:
+ void SetUp()
+ {
+ // We need a TERM set properly for editline to work as expected.
+ setenv("TERM", "vt100", 1);
+
+ // Validate the editline adapter.
+ EXPECT_TRUE(_el_adapter.IsValid());
+ if (!_el_adapter.IsValid())
+ return;
+
+ // Dump output.
+ _sp_output_thread.reset(new std::thread([&] { _el_adapter.ConsumeAllOutput(); }));
+ }
+
+ void TearDown()
+ {
+ _el_adapter.CloseInput();
+ if (_sp_output_thread)
+ _sp_output_thread->join();
+ }
- // Dump output.
- std::thread el_output_thread( [&] { el_adapter.ConsumeAllOutput (); });
+ EditlineAdapter &GetEditlineAdapter() { return _el_adapter; }
+};
+TEST_F(EditlineTestFixture, EditlineReceivesSingleLineText)
+{
// Send it some text via our virtual keyboard.
const std::string input_text ("Hello, world");
- EXPECT_TRUE (el_adapter.SendLine (input_text));
+ EXPECT_TRUE(GetEditlineAdapter().SendLine(input_text));
// Verify editline sees what we put in.
std::string el_reported_line;
bool input_interrupted = false;
- const bool received_line = el_adapter.GetLine (el_reported_line, input_interrupted, TIMEOUT_MILLIS);
+ const bool received_line = GetEditlineAdapter().GetLine(el_reported_line, input_interrupted, TIMEOUT_MILLIS);
EXPECT_TRUE (received_line);
EXPECT_FALSE (input_interrupted);
EXPECT_EQ (input_text, el_reported_line);
-
- el_adapter.CloseInput();
- el_output_thread.join();
}
-TEST (EditlineTest, EditlineReceivesMultiLineText)
+TEST_F(EditlineTestFixture, EditlineReceivesMultiLineText)
{
- setenv ("TERM", "vt100", 1);
-
- // Create an editline.
- EditlineAdapter el_adapter;
- EXPECT_TRUE (el_adapter.IsValid ());
- if (!el_adapter.IsValid ())
- return;
-
- // Stick editline output/error dumpers on separate threads.
- std::thread el_output_thread( [&] { el_adapter.ConsumeAllOutput (); });
-
// Send it some text via our virtual keyboard.
std::vector<std::string> input_lines;
input_lines.push_back ("int foo()");
@@ -344,25 +351,22 @@ TEST (EditlineTest, EditlineReceivesMultiLineText)
input_lines.push_back ("}");
input_lines.push_back ("");
- EXPECT_TRUE (el_adapter.SendLines (input_lines));
+ EXPECT_TRUE(GetEditlineAdapter().SendLines(input_lines));
// Verify editline sees what we put in.
lldb_private::StringList el_reported_lines;
bool input_interrupted = false;
- EXPECT_TRUE (el_adapter.GetLines (el_reported_lines, input_interrupted, TIMEOUT_MILLIS));
+ EXPECT_TRUE(GetEditlineAdapter().GetLines(el_reported_lines, input_interrupted, TIMEOUT_MILLIS));
EXPECT_FALSE (input_interrupted);
// Without any auto indentation support, our output should directly match our input.
EXPECT_EQ (input_lines.size (), el_reported_lines.GetSize ());
if (input_lines.size () == el_reported_lines.GetSize ())
{
- for (auto i = 0; i < input_lines.size(); ++i)
+ for (size_t i = 0; i < input_lines.size(); ++i)
EXPECT_EQ (input_lines[i], el_reported_lines[i]);
}
-
- el_adapter.CloseInput();
- el_output_thread.join();
}
#endif
diff --git a/unittests/Host/CMakeLists.txt b/unittests/Host/CMakeLists.txt
index b4739e113f480..be0450874203b 100644
--- a/unittests/Host/CMakeLists.txt
+++ b/unittests/Host/CMakeLists.txt
@@ -1,4 +1,5 @@
add_lldb_unittest(HostTests
+ FileSpecTest.cpp
SocketAddressTest.cpp
SocketTest.cpp
SymbolsTest.cpp
diff --git a/unittests/Host/FileSpecTest.cpp b/unittests/Host/FileSpecTest.cpp
new file mode 100644
index 0000000000000..4e619529773f3
--- /dev/null
+++ b/unittests/Host/FileSpecTest.cpp
@@ -0,0 +1,111 @@
+//===-- FileSpecTest.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Host/FileSpec.h"
+
+using namespace lldb_private;
+
+TEST(FileSpecTest, FileAndDirectoryComponents)
+{
+ FileSpec fs_posix("/foo/bar", false, FileSpec::ePathSyntaxPosix);
+ EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
+ EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
+ EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
+
+ FileSpec fs_windows("F:\\bar", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:\\bar", fs_windows.GetCString());
+ // EXPECT_STREQ("F:\\", fs_windows.GetDirectory().GetCString()); // It returns "F:/"
+ EXPECT_STREQ("bar", fs_windows.GetFilename().GetCString());
+
+ FileSpec fs_posix_root("/", false, FileSpec::ePathSyntaxPosix);
+ EXPECT_STREQ("/", fs_posix_root.GetCString());
+ EXPECT_EQ(nullptr, fs_posix_root.GetDirectory().GetCString());
+ EXPECT_STREQ("/", fs_posix_root.GetFilename().GetCString());
+
+ FileSpec fs_windows_drive("F:", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:", fs_windows_drive.GetCString());
+ EXPECT_EQ(nullptr, fs_windows_drive.GetDirectory().GetCString());
+ EXPECT_STREQ("F:", fs_windows_drive.GetFilename().GetCString());
+
+ FileSpec fs_windows_root("F:\\", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:\\", fs_windows_root.GetCString());
+ EXPECT_STREQ("F:", fs_windows_root.GetDirectory().GetCString());
+ // EXPECT_STREQ("\\", fs_windows_root.GetFilename().GetCString()); // It returns "/"
+
+ FileSpec fs_posix_long("/foo/bar/baz", false, FileSpec::ePathSyntaxPosix);
+ EXPECT_STREQ("/foo/bar/baz", fs_posix_long.GetCString());
+ EXPECT_STREQ("/foo/bar", fs_posix_long.GetDirectory().GetCString());
+ EXPECT_STREQ("baz", fs_posix_long.GetFilename().GetCString());
+
+ FileSpec fs_windows_long("F:\\bar\\baz", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:\\bar\\baz", fs_windows_long.GetCString());
+ // EXPECT_STREQ("F:\\bar", fs_windows_long.GetDirectory().GetCString()); // It returns "F:/bar"
+ EXPECT_STREQ("baz", fs_windows_long.GetFilename().GetCString());
+
+ FileSpec fs_posix_trailing_slash("/foo/bar/", false, FileSpec::ePathSyntaxPosix);
+ EXPECT_STREQ("/foo/bar/.", fs_posix_trailing_slash.GetCString());
+ EXPECT_STREQ("/foo/bar", fs_posix_trailing_slash.GetDirectory().GetCString());
+ EXPECT_STREQ(".", fs_posix_trailing_slash.GetFilename().GetCString());
+
+ FileSpec fs_windows_trailing_slash("F:\\bar\\", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:\\bar\\.", fs_windows_trailing_slash.GetCString());
+ // EXPECT_STREQ("F:\\bar", fs_windows_trailing_slash.GetDirectory().GetCString()); // It returns "F:/bar"
+ EXPECT_STREQ(".", fs_windows_trailing_slash.GetFilename().GetCString());
+}
+
+TEST(FileSpecTest, AppendPathComponent)
+{
+ FileSpec fs_posix("/foo", false, FileSpec::ePathSyntaxPosix);
+ fs_posix.AppendPathComponent("bar");
+ EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
+ EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
+ EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
+
+ FileSpec fs_windows("F:\\bar", false, FileSpec::ePathSyntaxWindows);
+ fs_windows.AppendPathComponent("baz");
+ EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
+ // EXPECT_STREQ("F:\\bar", fs_windows.GetDirectory().GetCString()); // It returns "F:/bar"
+ EXPECT_STREQ("baz", fs_windows.GetFilename().GetCString());
+
+ FileSpec fs_posix_root("/", false, FileSpec::ePathSyntaxPosix);
+ fs_posix_root.AppendPathComponent("bar");
+ EXPECT_STREQ("/bar", fs_posix_root.GetCString());
+ EXPECT_STREQ("/", fs_posix_root.GetDirectory().GetCString());
+ EXPECT_STREQ("bar", fs_posix_root.GetFilename().GetCString());
+
+ FileSpec fs_windows_root("F:\\", false, FileSpec::ePathSyntaxWindows);
+ fs_windows_root.AppendPathComponent("bar");
+ EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
+ // EXPECT_STREQ("F:\\", fs_windows_root.GetDirectory().GetCString()); // It returns "F:/"
+ EXPECT_STREQ("bar", fs_windows_root.GetFilename().GetCString());
+}
+
+TEST(FileSpecTest, CopyByAppendingPathComponent)
+{
+ FileSpec fs = FileSpec("/foo", false, FileSpec::ePathSyntaxPosix).CopyByAppendingPathComponent("bar");
+ EXPECT_STREQ("/foo/bar", fs.GetCString());
+ EXPECT_STREQ("/foo", fs.GetDirectory().GetCString());
+ EXPECT_STREQ("bar", fs.GetFilename().GetCString());
+}
+
+TEST(FileSpecTest, Equal)
+{
+ FileSpec backward("C:\\foo\\bar", false, FileSpec::ePathSyntaxWindows);
+ FileSpec forward("C:/foo/bar", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_EQ(forward, backward);
+
+ const bool full_match = true;
+ const bool remove_backup_dots = true;
+ EXPECT_TRUE(FileSpec::Equal(forward, backward, full_match, remove_backup_dots));
+ EXPECT_TRUE(FileSpec::Equal(forward, backward, full_match, !remove_backup_dots));
+ EXPECT_TRUE(FileSpec::Equal(forward, backward, !full_match, remove_backup_dots));
+ EXPECT_TRUE(FileSpec::Equal(forward, backward, !full_match, !remove_backup_dots));
+}
diff --git a/unittests/Host/SocketAddressTest.cpp b/unittests/Host/SocketAddressTest.cpp
index bd6bda13f4498..6b27e04ce7027 100644
--- a/unittests/Host/SocketAddressTest.cpp
+++ b/unittests/Host/SocketAddressTest.cpp
@@ -33,11 +33,8 @@ TEST_F (SocketAddressTest, Set)
ASSERT_EQ (0, sa.GetPort ());
ASSERT_TRUE (sa.SetToLocalhost (AF_INET6, 1139));
-#ifdef _WIN32
- ASSERT_STREQ ("0:0:0:0:0:0:0:1", sa.GetIPAddress ().c_str ());
-#else
- ASSERT_STREQ ("::1", sa.GetIPAddress ().c_str ());
-#endif
+ ASSERT_TRUE(sa.GetIPAddress() == "::1" || sa.GetIPAddress() == "0:0:0:0:0:0:0:1") << "Address was: "
+ << sa.GetIPAddress();
ASSERT_EQ (1139, sa.GetPort ());
}
diff --git a/unittests/Host/SocketTest.cpp b/unittests/Host/SocketTest.cpp
index ebb2f319a9c5d..e3e5227447600 100644
--- a/unittests/Host/SocketTest.cpp
+++ b/unittests/Host/SocketTest.cpp
@@ -116,7 +116,11 @@ TEST_F (SocketTest, DecodeHostAndPort)
EXPECT_FALSE (Socket::DecodeHostAndPort ("google.com:-1138", host_str, port_str, port, &error));
EXPECT_TRUE (error.Fail ());
EXPECT_STREQ ("invalid host:port specification: 'google.com:-1138'", error.AsCString ());
-
+
+ EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:65536", host_str, port_str, port, &error));
+ EXPECT_TRUE(error.Fail());
+ EXPECT_STREQ("invalid host:port specification: 'google.com:65536'", error.AsCString());
+
EXPECT_TRUE (Socket::DecodeHostAndPort ("12345", host_str, port_str, port, &error));
EXPECT_STREQ ("", host_str.c_str ());
EXPECT_STREQ ("12345", port_str.c_str ());
@@ -128,6 +132,12 @@ TEST_F (SocketTest, DecodeHostAndPort)
EXPECT_STREQ ("0", port_str.c_str ());
EXPECT_EQ (0, port);
EXPECT_TRUE (error.Success ());
+
+ EXPECT_TRUE(Socket::DecodeHostAndPort("*:65535", host_str, port_str, port, &error));
+ EXPECT_STREQ("*", host_str.c_str());
+ EXPECT_STREQ("65535", port_str.c_str());
+ EXPECT_EQ(65535, port);
+ EXPECT_TRUE(error.Success());
}
#ifndef LLDB_DISABLE_POSIX
diff --git a/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp b/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp
index 605f0233e876a..c239a1601b32f 100644
--- a/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp
+++ b/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp
@@ -209,14 +209,13 @@ TEST_F(PythonDataObjectsTest, TestPythonBytes)
PyObject *py_bytes = PyBytes_FromString(test_bytes);
EXPECT_TRUE(PythonBytes::Check(py_bytes));
PythonBytes python_bytes(PyRefType::Owned, py_bytes);
- EXPECT_EQ(PyObjectType::Bytes, python_bytes.GetObjectType());
#if PY_MAJOR_VERSION < 3
EXPECT_TRUE(PythonString::Check(py_bytes));
EXPECT_EQ(PyObjectType::String, python_bytes.GetObjectType());
#else
EXPECT_FALSE(PythonString::Check(py_bytes));
- EXPECT_NE(PyObjectType::String, python_bytes.GetObjectType());
+ EXPECT_EQ(PyObjectType::Bytes, python_bytes.GetObjectType());
#endif
llvm::ArrayRef<uint8_t> bytes = python_bytes.GetBytes();
@@ -224,13 +223,26 @@ TEST_F(PythonDataObjectsTest, TestPythonBytes)
EXPECT_EQ(0, ::memcmp(bytes.data(), test_bytes, bytes.size()));
}
+TEST_F(PythonDataObjectsTest, TestPythonByteArray)
+{
+ static const char *test_bytes = "PythonDataObjectsTest::TestPythonByteArray";
+ llvm::StringRef orig_bytes(test_bytes);
+ PyObject *py_bytes = PyByteArray_FromStringAndSize(test_bytes, orig_bytes.size());
+ EXPECT_TRUE(PythonByteArray::Check(py_bytes));
+ PythonByteArray python_bytes(PyRefType::Owned, py_bytes);
+ EXPECT_EQ(PyObjectType::ByteArray, python_bytes.GetObjectType());
+
+ llvm::ArrayRef<uint8_t> after_bytes = python_bytes.GetBytes();
+ EXPECT_EQ(after_bytes.size(), orig_bytes.size());
+ EXPECT_EQ(0, ::memcmp(orig_bytes.data(), test_bytes, orig_bytes.size()));
+}
+
TEST_F(PythonDataObjectsTest, TestPythonString)
{
// Test that strings behave correctly when wrapped by a PythonString.
static const char *test_string = "PythonDataObjectsTest::TestPythonString1";
static const char *test_string2 = "PythonDataObjectsTest::TestPythonString2";
- static const char *test_string3 = "PythonDataObjectsTest::TestPythonString3";
#if PY_MAJOR_VERSION < 3
// Verify that `PythonString` works correctly when given a PyString object.
@@ -252,8 +264,8 @@ TEST_F(PythonDataObjectsTest, TestPythonString)
// Test that creating a `PythonString` object works correctly with the
// string constructor
- PythonString constructed_string(test_string3);
- EXPECT_STREQ(test_string3, constructed_string.GetString().str().c_str());
+ PythonString constructed_string(test_string2);
+ EXPECT_STREQ(test_string2, constructed_string.GetString().str().c_str());
}
TEST_F(PythonDataObjectsTest, TestPythonStringToStr)
@@ -275,7 +287,7 @@ TEST_F(PythonDataObjectsTest, TestPythonIntegerToStructuredInteger)
{
PythonInteger integer(7);
auto int_sp = integer.CreateStructuredInteger();
- EXPECT_EQ(7, int_sp->GetValue());
+ EXPECT_EQ(7U, int_sp->GetValue());
}
TEST_F(PythonDataObjectsTest, TestPythonStringToStructuredString)
@@ -290,7 +302,7 @@ TEST_F(PythonDataObjectsTest, TestPythonListValueEquality)
{
// Test that a list which is built through the native
// Python API behaves correctly when wrapped by a PythonList.
- static const int list_size = 2;
+ static const unsigned list_size = 2;
static const long long_value0 = 5;
static const char *const string_value1 = "String Index 1";
@@ -302,7 +314,7 @@ TEST_F(PythonDataObjectsTest, TestPythonListValueEquality)
list_items[0].Reset(PythonInteger(long_value0));
list_items[1].Reset(PythonString(string_value1));
- for (int i = 0; i < list_size; ++i)
+ for (unsigned i = 0; i < list_size; ++i)
list.SetItemAtIndex(i, list_items[i]);
EXPECT_EQ(list_size, list.GetSize());
@@ -335,7 +347,7 @@ TEST_F(PythonDataObjectsTest, TestPythonListManipulation)
list.AppendItem(integer);
list.AppendItem(string);
- EXPECT_EQ(2, list.GetSize());
+ EXPECT_EQ(2U, list.GetSize());
// Verify that the values match
PythonObject chk_value1 = list.GetItemAtIndex(0);
@@ -366,17 +378,17 @@ TEST_F(PythonDataObjectsTest, TestPythonListToStructuredList)
auto int_sp = array_sp->GetItemAtIndex(0)->GetAsInteger();
auto string_sp = array_sp->GetItemAtIndex(1)->GetAsString();
- EXPECT_EQ(long_value0, int_sp->GetValue());
+ EXPECT_EQ(long_value0, long(int_sp->GetValue()));
EXPECT_STREQ(string_value1, string_sp->GetValue().c_str());
}
TEST_F(PythonDataObjectsTest, TestPythonTupleSize)
{
PythonTuple tuple(PyInitialValue::Empty);
- EXPECT_EQ(0, tuple.GetSize());
+ EXPECT_EQ(0U, tuple.GetSize());
tuple = PythonTuple(3);
- EXPECT_EQ(3, tuple.GetSize());
+ EXPECT_EQ(3U, tuple.GetSize());
}
TEST_F(PythonDataObjectsTest, TestPythonTupleValues)
@@ -402,7 +414,7 @@ TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList)
PythonString string_value("Test");
PythonObject none_value(PyRefType::Borrowed, Py_None);
PythonTuple tuple{ int_value, string_value, none_value };
- EXPECT_EQ(3, tuple.GetSize());
+ EXPECT_EQ(3U, tuple.GetSize());
EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
@@ -416,7 +428,7 @@ TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList2)
PythonObject none_value(PyRefType::Borrowed, Py_None);
PythonTuple tuple{ int_value.get(), string_value.get(), none_value.get() };
- EXPECT_EQ(3, tuple.GetSize());
+ EXPECT_EQ(3U, tuple.GetSize());
EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
@@ -440,7 +452,7 @@ TEST_F(PythonDataObjectsTest, TestPythonDictionaryValueEquality)
{
// Test that a dictionary which is built through the native
// Python API behaves correctly when wrapped by a PythonDictionary.
- static const int dict_entries = 2;
+ static const unsigned dict_entries = 2;
const char *key_0 = "Key 0";
int key_1 = 1;
const int value_0 = 0;
@@ -458,7 +470,7 @@ TEST_F(PythonDataObjectsTest, TestPythonDictionaryValueEquality)
EXPECT_TRUE(PythonDictionary::Check(py_dict));
PythonDictionary dict(PyRefType::Owned, py_dict);
- for (int i = 0; i < dict_entries; ++i)
+ for (unsigned i = 0; i < dict_entries; ++i)
PyDict_SetItem(py_dict, py_keys[i].get(), py_values[i].get());
EXPECT_EQ(dict.GetSize(), dict_entries);
EXPECT_EQ(PyObjectType::Dictionary, dict.GetObjectType());
@@ -480,7 +492,7 @@ TEST_F(PythonDataObjectsTest, TestPythonDictionaryManipulation)
{
// Test that manipulation of a dictionary behaves correctly when wrapped
// by a PythonDictionary.
- static const int dict_entries = 2;
+ static const unsigned dict_entries = 2;
const char *const key_0 = "Key 0";
const char *const key_1 = "Key 1";
@@ -527,7 +539,7 @@ TEST_F(PythonDataObjectsTest, TestPythonDictionaryToStructuredDictionary)
dict.SetItemForKey(PythonString(string_key1), PythonInteger(int_value1));
auto dict_sp = dict.CreateStructuredDictionary();
- EXPECT_EQ(2, dict_sp->GetSize());
+ EXPECT_EQ(2U, dict_sp->GetSize());
EXPECT_TRUE(dict_sp->HasKey(string_key0));
EXPECT_TRUE(dict_sp->HasKey(string_key1));
@@ -536,7 +548,7 @@ TEST_F(PythonDataObjectsTest, TestPythonDictionaryToStructuredDictionary)
auto int_sp = dict_sp->GetValueForKey(string_key1)->GetAsInteger();
EXPECT_STREQ(string_value0, string_sp->GetValue().c_str());
- EXPECT_EQ(int_value1, int_sp->GetValue());
+ EXPECT_EQ(int_value1, long(int_sp->GetValue()));
}
TEST_F(PythonDataObjectsTest, TestPythonCallableCheck)
@@ -560,7 +572,7 @@ TEST_F(PythonDataObjectsTest, TestPythonCallableInvoke)
EXPECT_TRUE(PythonList::Check(result.get()));
auto list_result = result.AsType<PythonList>();
- EXPECT_EQ(3, list_result.GetSize());
+ EXPECT_EQ(3U, list_result.GetSize());
EXPECT_EQ(one.get(), list_result.GetItemAtIndex(0).get());
EXPECT_EQ(two.get(), list_result.GetItemAtIndex(1).get());
EXPECT_EQ(three.get(), list_result.GetItemAtIndex(2).get());
@@ -582,4 +594,4 @@ TEST_F(PythonDataObjectsTest, TestObjectAttributes)
PythonInteger numerator_attr = py_int.GetAttributeValue("numerator").AsType<PythonInteger>();
EXPECT_TRUE(numerator_attr.IsAllocated());
EXPECT_EQ(42, numerator_attr.GetInteger());
-} \ No newline at end of file
+}
diff --git a/unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp b/unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp
index a0a6f986cef6c..ddac220c79541 100644
--- a/unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp
+++ b/unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp
@@ -171,4 +171,4 @@ TEST_F(PythonExceptionStateTest, TestAutoRestoreChanged)
EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
PyErr_Clear();
-} \ No newline at end of file
+}
diff --git a/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
index 3d1727dc1c25a..5eb1c72598a8c 100644
--- a/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ b/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -24,6 +24,7 @@ PythonTestSuite::SetUp()
// ScriptInterpreterPython::Initialize() depends on HostInfo being
// initializedso it can compute the python directory etc.
ScriptInterpreterPython::Initialize();
+ ScriptInterpreterPython::InitializePrivate();
// Although we don't care about concurrency for the purposes of running
// this test suite, Python requires the GIL to be locked even for
diff --git a/unittests/Symbol/CMakeLists.txt b/unittests/Symbol/CMakeLists.txt
new file mode 100644
index 0000000000000..ef41f3fd62a87
--- /dev/null
+++ b/unittests/Symbol/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_unittest(SymbolTests
+ TestClangASTContext.cpp
+ )
diff --git a/unittests/Symbol/TestClangASTContext.cpp b/unittests/Symbol/TestClangASTContext.cpp
new file mode 100644
index 0000000000000..3f166ab9cc724
--- /dev/null
+++ b/unittests/Symbol/TestClangASTContext.cpp
@@ -0,0 +1,315 @@
+//===-- TestClangASTContext.cpp ---------------------------------------*- C++ -*-===//
+
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangUtil.h"
+#include "lldb/Symbol/Declaration.h"
+#include "lldb/Symbol/GoASTContext.h"
+
+using namespace clang;
+using namespace lldb;
+using namespace lldb_private;
+
+class TestClangASTContext : public testing::Test
+{
+public:
+ static void
+ SetUpTestCase()
+ {
+ HostInfo::Initialize();
+ }
+
+ static void
+ TearDownTestCase()
+ {
+ HostInfo::Terminate();
+ }
+
+ virtual void
+ SetUp() override
+ {
+ std::string triple = HostInfo::GetTargetTriple();
+ m_ast.reset(new ClangASTContext(triple.c_str()));
+ }
+
+ virtual void
+ TearDown() override
+ {
+ m_ast.reset();
+ }
+
+protected:
+ std::unique_ptr<ClangASTContext> m_ast;
+
+ QualType
+ GetBasicQualType(BasicType type) const
+ {
+ return ClangUtil::GetQualType(m_ast->GetBasicTypeFromAST(type));
+ }
+
+ QualType
+ GetBasicQualType(const char *name) const
+ {
+ return ClangUtil::GetQualType(m_ast->GetBuiltinTypeByName(ConstString(name)));
+ }
+};
+
+TEST_F(TestClangASTContext, TestGetBasicTypeFromEnum)
+{
+ clang::ASTContext *context = m_ast->getASTContext();
+
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeBool), context->BoolTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar), context->CharTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar16), context->Char16Ty));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar32), context->Char32Ty));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeDouble), context->DoubleTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeDoubleComplex), context->DoubleComplexTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeFloat), context->FloatTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeFloatComplex), context->FloatComplexTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeHalf), context->HalfTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeInt), context->IntTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeInt128), context->Int128Ty));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLong), context->LongTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongDouble), context->LongDoubleTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongDoubleComplex), context->LongDoubleComplexTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongLong), context->LongLongTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeNullPtr), context->NullPtrTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCClass), context->getObjCClassType()));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCID), context->getObjCIdType()));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCSel), context->getObjCSelType()));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeShort), context->ShortTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeSignedChar), context->SignedCharTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedChar), context->UnsignedCharTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedInt), context->UnsignedIntTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedInt128), context->UnsignedInt128Ty));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedLong), context->UnsignedLongTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedLongLong), context->UnsignedLongLongTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedShort), context->UnsignedShortTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeVoid), context->VoidTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeWChar), context->WCharTy));
+}
+
+TEST_F(TestClangASTContext, TestGetBasicTypeFromName)
+{
+ EXPECT_EQ(GetBasicQualType(eBasicTypeChar), GetBasicQualType("char"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeSignedChar), GetBasicQualType("signed char"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedChar), GetBasicQualType("unsigned char"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeWChar), GetBasicQualType("wchar_t"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeSignedWChar), GetBasicQualType("signed wchar_t"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedWChar), GetBasicQualType("unsigned wchar_t"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort), GetBasicQualType("unsigned short"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort), GetBasicQualType("unsigned short int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("signed int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt), GetBasicQualType("unsigned int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt), GetBasicQualType("unsigned"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong), GetBasicQualType("unsigned long"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong), GetBasicQualType("unsigned long int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong), GetBasicQualType("long long"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong), GetBasicQualType("long long int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong), GetBasicQualType("unsigned long long"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong), GetBasicQualType("unsigned long long int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128_t"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt128), GetBasicQualType("__uint128_t"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeVoid), GetBasicQualType("void"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeBool), GetBasicQualType("bool"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeFloat), GetBasicQualType("float"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeDouble), GetBasicQualType("double"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeLongDouble), GetBasicQualType("long double"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeObjCID), GetBasicQualType("id"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeObjCSel), GetBasicQualType("SEL"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeNullPtr), GetBasicQualType("nullptr"));
+}
+
+void
+VerifyEncodingAndBitSize(clang::ASTContext *context, lldb::Encoding encoding, int bit_size)
+{
+ CompilerType type = ClangASTContext::GetBuiltinTypeForEncodingAndBitSize(context, encoding, bit_size);
+ EXPECT_TRUE(type.IsValid());
+
+ QualType qtype = ClangUtil::GetQualType(type);
+ EXPECT_FALSE(qtype.isNull());
+ if (qtype.isNull())
+ return;
+
+ uint64_t actual_size = context->getTypeSize(qtype);
+ EXPECT_EQ(bit_size, actual_size);
+
+ const clang::Type *type_ptr = qtype.getTypePtr();
+ EXPECT_NE(nullptr, type_ptr);
+ if (!type_ptr)
+ return;
+
+ EXPECT_TRUE(type_ptr->isBuiltinType());
+ if (encoding == eEncodingSint)
+ EXPECT_TRUE(type_ptr->isSignedIntegerType());
+ else if (encoding == eEncodingUint)
+ EXPECT_TRUE(type_ptr->isUnsignedIntegerType());
+ else if (encoding == eEncodingIEEE754)
+ EXPECT_TRUE(type_ptr->isFloatingType());
+}
+
+TEST_F(TestClangASTContext, TestBuiltinTypeForEncodingAndBitSize)
+{
+ clang::ASTContext *context = m_ast->getASTContext();
+
+ // Make sure we can get types of every possible size in every possible encoding.
+ // We can't make any guarantee about which specific type we get, because the standard
+ // isn't that specific. We only need to make sure the compiler hands us some type that
+ // is both a builtin type and matches the requested bit size.
+ VerifyEncodingAndBitSize(context, eEncodingSint, 8);
+ VerifyEncodingAndBitSize(context, eEncodingSint, 16);
+ VerifyEncodingAndBitSize(context, eEncodingSint, 32);
+ VerifyEncodingAndBitSize(context, eEncodingSint, 64);
+ VerifyEncodingAndBitSize(context, eEncodingSint, 128);
+
+ VerifyEncodingAndBitSize(context, eEncodingUint, 8);
+ VerifyEncodingAndBitSize(context, eEncodingUint, 16);
+ VerifyEncodingAndBitSize(context, eEncodingUint, 32);
+ VerifyEncodingAndBitSize(context, eEncodingUint, 64);
+ VerifyEncodingAndBitSize(context, eEncodingUint, 128);
+
+ VerifyEncodingAndBitSize(context, eEncodingIEEE754, 32);
+ VerifyEncodingAndBitSize(context, eEncodingIEEE754, 64);
+}
+
+TEST_F(TestClangASTContext, TestIsClangType)
+{
+ clang::ASTContext *context = m_ast->getASTContext();
+ lldb::opaque_compiler_type_t bool_ctype = ClangASTContext::GetOpaqueCompilerType(context, lldb::eBasicTypeBool);
+ CompilerType bool_type(m_ast.get(), bool_ctype);
+ CompilerType record_type = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct,
+ lldb::eLanguageTypeC_plus_plus, nullptr);
+ // Clang builtin type and record type should pass
+ EXPECT_TRUE(ClangUtil::IsClangType(bool_type));
+ EXPECT_TRUE(ClangUtil::IsClangType(record_type));
+
+ // Default constructed type should fail
+ EXPECT_FALSE(ClangUtil::IsClangType(CompilerType()));
+
+ // Go type should fail
+ GoASTContext go_ast;
+ CompilerType go_type(&go_ast, bool_ctype);
+ EXPECT_FALSE(ClangUtil::IsClangType(go_type));
+}
+
+TEST_F(TestClangASTContext, TestRemoveFastQualifiers)
+{
+ CompilerType record_type = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct,
+ lldb::eLanguageTypeC_plus_plus, nullptr);
+ QualType qt;
+
+ qt = ClangUtil::GetQualType(record_type);
+ EXPECT_EQ(0, qt.getLocalFastQualifiers());
+ record_type = record_type.AddConstModifier();
+ record_type = record_type.AddVolatileModifier();
+ record_type = record_type.AddRestrictModifier();
+ qt = ClangUtil::GetQualType(record_type);
+ EXPECT_NE(0, qt.getLocalFastQualifiers());
+ record_type = ClangUtil::RemoveFastQualifiers(record_type);
+ qt = ClangUtil::GetQualType(record_type);
+ EXPECT_EQ(0, qt.getLocalFastQualifiers());
+}
+
+TEST_F(TestClangASTContext, TestConvertAccessTypeToAccessSpecifier)
+{
+ EXPECT_EQ(AS_none, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessNone));
+ EXPECT_EQ(AS_none, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessPackage));
+ EXPECT_EQ(AS_public, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessPublic));
+ EXPECT_EQ(AS_private, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessPrivate));
+ EXPECT_EQ(AS_protected, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessProtected));
+}
+
+TEST_F(TestClangASTContext, TestUnifyAccessSpecifiers)
+{
+ // Unifying two of the same type should return the same type
+ EXPECT_EQ(AS_public, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_public));
+ EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_private));
+ EXPECT_EQ(AS_protected, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_protected));
+
+ // Otherwise the result should be the strictest of the two.
+ EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_public));
+ EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_protected));
+ EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_private));
+ EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_private));
+ EXPECT_EQ(AS_protected, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_public));
+ EXPECT_EQ(AS_protected, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_protected));
+
+ // None is stricter than everything (by convention)
+ EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_public));
+ EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_protected));
+ EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_private));
+ EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_none));
+ EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_none));
+ EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_none));
+}
+
+TEST_F(TestClangASTContext, TestRecordHasFields)
+{
+ CompilerType int_type = ClangASTContext::GetBasicType(m_ast->getASTContext(), eBasicTypeInt);
+
+ // Test that a record with no fields returns false
+ CompilerType empty_base = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "EmptyBase", clang::TTK_Struct,
+ lldb::eLanguageTypeC_plus_plus, nullptr);
+ ClangASTContext::StartTagDeclarationDefinition(empty_base);
+ ClangASTContext::CompleteTagDeclarationDefinition(empty_base);
+
+ RecordDecl *empty_base_decl = ClangASTContext::GetAsRecordDecl(empty_base);
+ EXPECT_NE(nullptr, empty_base_decl);
+ EXPECT_FALSE(ClangASTContext::RecordHasFields(empty_base_decl));
+
+ // Test that a record with direct fields returns true
+ CompilerType non_empty_base = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "NonEmptyBase",
+ clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
+ ClangASTContext::StartTagDeclarationDefinition(non_empty_base);
+ FieldDecl *non_empty_base_field_decl =
+ m_ast->AddFieldToRecordType(non_empty_base, "MyField", int_type, eAccessPublic, 0);
+ ClangASTContext::CompleteTagDeclarationDefinition(non_empty_base);
+ RecordDecl *non_empty_base_decl = ClangASTContext::GetAsRecordDecl(non_empty_base);
+ EXPECT_NE(nullptr, non_empty_base_decl);
+ EXPECT_NE(nullptr, non_empty_base_field_decl);
+ EXPECT_TRUE(ClangASTContext::RecordHasFields(non_empty_base_decl));
+
+ // Test that a record with no direct fields, but fields in a base returns true
+ CompilerType empty_derived = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "EmptyDerived",
+ clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
+ ClangASTContext::StartTagDeclarationDefinition(empty_derived);
+ CXXBaseSpecifier *non_empty_base_spec =
+ m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(), lldb::eAccessPublic, false, false);
+ bool result = m_ast->SetBaseClassesForClassType(empty_derived.GetOpaqueQualType(), &non_empty_base_spec, 1);
+ ClangASTContext::CompleteTagDeclarationDefinition(empty_derived);
+ EXPECT_TRUE(result);
+ CXXRecordDecl *empty_derived_non_empty_base_cxx_decl = m_ast->GetAsCXXRecordDecl(empty_derived.GetOpaqueQualType());
+ RecordDecl *empty_derived_non_empty_base_decl = ClangASTContext::GetAsRecordDecl(empty_derived);
+ EXPECT_EQ(1, ClangASTContext::GetNumBaseClasses(empty_derived_non_empty_base_cxx_decl, false));
+ EXPECT_TRUE(ClangASTContext::RecordHasFields(empty_derived_non_empty_base_decl));
+
+ // Test that a record with no direct fields, but fields in a virtual base returns true
+ CompilerType empty_derived2 = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "EmptyDerived2",
+ clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
+ ClangASTContext::StartTagDeclarationDefinition(empty_derived2);
+ CXXBaseSpecifier *non_empty_vbase_spec =
+ m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(), lldb::eAccessPublic, true, false);
+ result = m_ast->SetBaseClassesForClassType(empty_derived2.GetOpaqueQualType(), &non_empty_vbase_spec, 1);
+ ClangASTContext::CompleteTagDeclarationDefinition(empty_derived2);
+ EXPECT_TRUE(result);
+ CXXRecordDecl *empty_derived_non_empty_vbase_cxx_decl =
+ m_ast->GetAsCXXRecordDecl(empty_derived2.GetOpaqueQualType());
+ RecordDecl *empty_derived_non_empty_vbase_decl = ClangASTContext::GetAsRecordDecl(empty_derived2);
+ EXPECT_EQ(1, ClangASTContext::GetNumBaseClasses(empty_derived_non_empty_vbase_cxx_decl, false));
+ EXPECT_TRUE(ClangASTContext::RecordHasFields(empty_derived_non_empty_vbase_decl));
+}
diff --git a/unittests/SymbolFile/CMakeLists.txt b/unittests/SymbolFile/CMakeLists.txt
new file mode 100644
index 0000000000000..dcf9ebdb11619
--- /dev/null
+++ b/unittests/SymbolFile/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(PDB)
diff --git a/unittests/SymbolFile/PDB/CMakeLists.txt b/unittests/SymbolFile/PDB/CMakeLists.txt
new file mode 100644
index 0000000000000..fcfb5e3062c9d
--- /dev/null
+++ b/unittests/SymbolFile/PDB/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_lldb_unittest(SymbolFilePDBTests
+ SymbolFilePDBTests.cpp
+ )
+
+set(test_inputs
+ test-pdb.exe
+ test-pdb.pdb
+ test-dwarf.exe
+ test-pdb-types.exe
+ test-pdb-types.pdb)
+
+add_unittest_inputs(SymbolFilePDBTests "${test_inputs}")
diff --git a/unittests/SymbolFile/PDB/Inputs/test-dwarf.cpp b/unittests/SymbolFile/PDB/Inputs/test-dwarf.cpp
new file mode 100644
index 0000000000000..f86ff3d875b4a
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-dwarf.cpp
@@ -0,0 +1,14 @@
+// Compile with "cl /c /Zi /GR- test.cpp"
+// Link with "link test.obj /debug /nodefaultlib /entry:main /out:test.exe"
+
+int __cdecl _purecall(void)
+{
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+
+ return 0;
+}
diff --git a/unittests/SymbolFile/PDB/Inputs/test-dwarf.exe b/unittests/SymbolFile/PDB/Inputs/test-dwarf.exe
new file mode 100644
index 0000000000000..15e1910b4b8ba
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-dwarf.exe
Binary files differ
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb-alt.cpp b/unittests/SymbolFile/PDB/Inputs/test-pdb-alt.cpp
new file mode 100644
index 0000000000000..d36f15e53fb71
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb-alt.cpp
@@ -0,0 +1,9 @@
+// Compile with "cl /c /Zi /GR- test-pdb-alt.cpp"
+// Link with "link test-pdb.obj test-pdb-alt.obj /debug /nodefaultlib /entry:main /out:test-pdb.exe"
+
+#include "test-pdb.h"
+
+int bar(int n)
+{
+ return n-1;
+}
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb-nested.h b/unittests/SymbolFile/PDB/Inputs/test-pdb-nested.h
new file mode 100644
index 0000000000000..fc63b50d13c9d
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb-nested.h
@@ -0,0 +1,9 @@
+#ifndef TEST_PDB_NESTED_H
+#define TEST_PDB_NESTED_H
+
+inline int baz(int n)
+{
+ return n+1;
+}
+
+#endif \ No newline at end of file
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp b/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp
new file mode 100644
index 0000000000000..5e2fb77bc202d
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp
@@ -0,0 +1,86 @@
+// Compile with "cl /c /Zi /GR- /EHsc test-pdb-types.cpp"
+// Link with "link test-pdb-types.obj /debug /nodefaultlib /entry:main /out:test-pdb-types.exe"
+
+using namespace std;
+
+// Sizes of builtin types
+static const int sizeof_char = sizeof(char);
+static const int sizeof_uchar = sizeof(unsigned char);
+static const int sizeof_short = sizeof(short);
+static const int sizeof_ushort = sizeof(unsigned short);
+static const int sizeof_int = sizeof(int);
+static const int sizeof_uint = sizeof(unsigned int);
+static const int sizeof_long = sizeof(long);
+static const int sizeof_ulong = sizeof(unsigned long);
+static const int sizeof_longlong = sizeof(long long);
+static const int sizeof_ulonglong = sizeof(unsigned long long);
+static const int sizeof_int64 = sizeof(__int64);
+static const int sizeof_uint64 = sizeof(unsigned __int64);
+static const int sizeof_float = sizeof(float);
+static const int sizeof_double = sizeof(double);
+static const int sizeof_bool = sizeof(bool);
+static const int sizeof_wchar = sizeof(wchar_t);
+
+enum Enum
+{
+ EValue1 = 1,
+ EValue2 = 2,
+};
+
+enum ShortEnum : short
+{
+ ESValue1 = 1,
+ ESValue2 = 2
+};
+
+namespace NS
+{
+class NSClass
+{
+ float f;
+ double d;
+};
+}
+
+class Class
+{
+public:
+ class NestedClass
+ {
+ Enum e;
+ };
+ ShortEnum se;
+};
+
+int
+test_func(int a, int b)
+{
+ return a + b;
+}
+
+typedef Class ClassTypedef;
+typedef NS::NSClass NSClassTypedef;
+int GlobalArray[10];
+
+static const int sizeof_NSClass = sizeof(NS::NSClass);
+static const int sizeof_Class = sizeof(Class);
+static const int sizeof_NestedClass = sizeof(Class::NestedClass);
+static const int sizeof_Enum = sizeof(Enum);
+static const int sizeof_ShortEnum = sizeof(ShortEnum);
+static const int sizeof_ClassTypedef = sizeof(ClassTypedef);
+static const int sizeof_NSClassTypedef = sizeof(NSClassTypedef);
+static const int sizeof_GlobalArray = sizeof(GlobalArray);
+
+int
+main(int argc, char **argv)
+{
+ ShortEnum e1;
+ Enum e2;
+ Class c1;
+ Class::NestedClass c2;
+ NS::NSClass c3;
+
+ ClassTypedef t1;
+ NSClassTypedef t2;
+ return test_func(1, 2);
+}
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb-types.exe b/unittests/SymbolFile/PDB/Inputs/test-pdb-types.exe
new file mode 100644
index 0000000000000..21a4bd2b4ef53
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb-types.exe
Binary files differ
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb-types.pdb b/unittests/SymbolFile/PDB/Inputs/test-pdb-types.pdb
new file mode 100644
index 0000000000000..acf241bcb5d6c
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb-types.pdb
Binary files differ
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb.cpp b/unittests/SymbolFile/PDB/Inputs/test-pdb.cpp
new file mode 100644
index 0000000000000..c9bf057cfbfbe
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb.cpp
@@ -0,0 +1,15 @@
+// Compile with "cl /c /Zi /GR- test-pdb.cpp"
+// Link with "link test-pdb.obj /debug /nodefaultlib /entry:main /out:test-pdb.exe"
+
+#include "test-pdb.h"
+
+int __cdecl _purecall(void)
+{
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ return foo(argc) + bar(argc);
+}
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb.exe b/unittests/SymbolFile/PDB/Inputs/test-pdb.exe
new file mode 100644
index 0000000000000..3a2c64504ed93
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb.exe
Binary files differ
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb.h b/unittests/SymbolFile/PDB/Inputs/test-pdb.h
new file mode 100644
index 0000000000000..273343bb03b07
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb.h
@@ -0,0 +1,13 @@
+#ifndef TEST_PDB_H
+#define TEST_PDB_H
+
+#include "test-pdb-nested.h"
+
+int bar(int n);
+
+inline int foo(int n)
+{
+ return baz(n)+1;
+}
+
+#endif \ No newline at end of file
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb.pdb b/unittests/SymbolFile/PDB/Inputs/test-pdb.pdb
new file mode 100644
index 0000000000000..f43d334d215a7
--- /dev/null
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb.pdb
Binary files differ
diff --git a/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp b/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp
new file mode 100644
index 0000000000000..b303ae7bac4bc
--- /dev/null
+++ b/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp
@@ -0,0 +1,583 @@
+//===-- PythonDataObjectsTests.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
+
+#if defined(_MSC_VER)
+#include "lldb/Host/windows/windows.h"
+#include <objbase.h>
+#endif
+
+#include <algorithm>
+
+extern const char *TestMainArgv0;
+
+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(_MSC_VER)
+ ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+#endif
+
+ HostInfo::Initialize();
+ ObjectFilePECOFF::Initialize();
+ SymbolFileDWARF::Initialize();
+ ClangASTContext::Initialize();
+ SymbolFilePDB::Initialize();
+
+ llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0);
+ llvm::SmallString<128> inputs_folder = exe_folder;
+ llvm::sys::path::append(inputs_folder, "Inputs");
+
+ m_pdb_test_exe = inputs_folder;
+ m_dwarf_test_exe = inputs_folder;
+ m_types_test_exe = inputs_folder;
+ llvm::sys::path::append(m_pdb_test_exe, "test-pdb.exe");
+ llvm::sys::path::append(m_dwarf_test_exe, "test-dwarf.exe");
+ llvm::sys::path::append(m_types_test_exe, "test-pdb-types.exe");
+ }
+
+ void
+ TearDown() override
+ {
+ SymbolFilePDB::Terminate();
+ ClangASTContext::Initialize();
+ SymbolFileDWARF::Terminate();
+ ObjectFilePECOFF::Terminate();
+ HostInfo::Terminate();
+
+#if defined(_MSC_VER)
+ ::CoUninitialize();
+#endif
+ }
+
+protected:
+ llvm::SmallString<128> m_pdb_test_exe;
+ llvm::SmallString<128> m_dwarf_test_exe;
+ llvm::SmallString<128> 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, spec))
+ return true;
+ }
+ return false;
+ }
+
+ int
+ GetGlobalConstantInteger(const 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;
+ }
+ }
+};
+
+#if defined(HAVE_DIA_SDK)
+#define REQUIRES_DIA_SDK(TestName) TestName
+#else
+#define REQUIRES_DIA_SDK(TestName) DISABLED_##TestName
+#endif
+
+TEST_F(SymbolFilePDBTests, TestAbilitiesForDWARF)
+{
+ // Test that when we have Dwarf debug info, SymbolFileDWARF is used.
+ FileSpec fspec(m_dwarf_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+ EXPECT_NE(nullptr, symfile);
+ EXPECT_EQ(symfile->GetPluginName(), SymbolFileDWARF::GetPluginNameStatic());
+
+ uint32_t expected_abilities = SymbolFile::kAllAbilities;
+ EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
+}
+
+TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestAbilitiesForPDB))
+{
+ // Test that when we have PDB debug info, SymbolFilePDB is used.
+ FileSpec fspec(m_pdb_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+ EXPECT_NE(nullptr, symfile);
+ EXPECT_EQ(symfile->GetPluginName(), SymbolFilePDB::GetPluginNameStatic());
+
+ uint32_t expected_abilities = SymbolFile::CompileUnits | SymbolFile::LineTables;
+ EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
+}
+
+TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(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.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec header_spec("test-pdb.cpp", false);
+ 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, REQUIRES_DIA_SDK(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.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec header_spec(R"spec(D:\src\llvm\tools\lldb\unittests\SymbolFile\PDB\Inputs\test-pdb.cpp)spec", false);
+ 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, REQUIRES_DIA_SDK(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.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec header_specs[] = {FileSpec("test-pdb.h", false), FileSpec("test-pdb-nested.h", false)};
+ FileSpec main_cpp_spec("test-pdb.cpp", false);
+ FileSpec alt_cpp_spec("test-pdb-alt.cpp", false);
+ 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, REQUIRES_DIA_SDK(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.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec header_specs[] = {FileSpec("test-pdb.h", false), FileSpec("test-pdb-nested.h", false)};
+ 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, REQUIRES_DIA_SDK(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.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec source_file("test-pdb.cpp", false);
+ FileSpec header1("test-pdb.h", false);
+ FileSpec header2("test-pdb-nested.h", false);
+ uint32_t cus = symfile->GetNumCompileUnits();
+ EXPECT_EQ(2u, cus);
+
+ SymbolContextList sc_list;
+ uint32_t 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, REQUIRES_DIA_SDK(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.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec source_file("test-pdb.cpp", false);
+ FileSpec header1("test-pdb.h", false);
+ FileSpec header2("test-pdb-nested.h", false);
+ uint32_t cus = symfile->GetNumCompileUnits();
+ EXPECT_EQ(2u, cus);
+
+ SymbolContextList sc_list;
+ uint32_t 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, REQUIRES_DIA_SDK(TestSimpleClassTypes))
+{
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("Class"), nullptr, false, 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(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
+ EXPECT_EQ(uint64_t(GetGlobalConstantInteger(session, "sizeof_Class")), udt_type->GetByteSize());
+}
+
+TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestNestedClassTypes))
+{
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("Class::NestedClass"), nullptr, false, 0, searched_files, results));
+ EXPECT_EQ(1u, results.GetSize());
+ lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
+ EXPECT_EQ(ConstString("Class::NestedClass"), udt_type->GetName());
+ CompilerType compiler_type = udt_type->GetForwardCompilerType();
+ EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
+ EXPECT_EQ(uint64_t(GetGlobalConstantInteger(session, "sizeof_NestedClass")), udt_type->GetByteSize());
+}
+
+TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestClassInNamespace))
+{
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("NS::NSClass"), nullptr, false, 0, searched_files, results));
+ EXPECT_EQ(1u, results.GetSize());
+ lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
+ EXPECT_EQ(ConstString("NS::NSClass"), udt_type->GetName());
+ CompilerType compiler_type = udt_type->GetForwardCompilerType();
+ EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
+ EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NSClass"), udt_type->GetByteSize());
+}
+
+TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestEnumTypes))
+{
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ const char *EnumsToCheck[] = {"Enum", "ShortEnum"};
+ for (auto Enum : EnumsToCheck)
+ {
+ TypeMap results;
+ EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString(Enum), nullptr, false, 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(ClangASTContext::IsEnumType(compiler_type.GetOpaqueQualType()));
+ clang::EnumDecl *enum_decl = ClangASTContext::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.c_str()), enum_type->GetByteSize());
+ }
+}
+
+TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(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, REQUIRES_DIA_SDK(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, REQUIRES_DIA_SDK(TestTypedefs))
+{
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+
+ const char *TypedefsToCheck[] = {"ClassTypedef", "NSClassTypedef"};
+ for (auto Typedef : TypedefsToCheck)
+ {
+ TypeMap results;
+ EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString(Typedef), nullptr, false, 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();
+ ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(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.c_str()), typedef_type->GetByteSize());
+ }
+}
+
+TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestRegexNameMatch))
+{
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ uint32_t num_results = symfile->FindTypes(sc, ConstString(".*"), nullptr, false, 0, searched_files, results);
+ EXPECT_GT(num_results, 1u);
+ EXPECT_EQ(num_results, results.GetSize());
+}
+
+TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestMaxMatches))
+{
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ uint32_t num_results = symfile->FindTypes(sc, ConstString(".*"), nullptr, false, 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 iterations = std::min(num_results, 10u);
+ for (uint32_t i = 1; i <= iterations; ++i)
+ {
+ uint32_t num_limited_results = symfile->FindTypes(sc, ConstString(".*"), nullptr, false, i, searched_files, results);
+ EXPECT_EQ(i, num_limited_results);
+ EXPECT_EQ(num_limited_results, results.GetSize());
+ }
+}
+
+TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestNullName))
+{
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ uint32_t num_results = symfile->FindTypes(sc, ConstString(), nullptr, false, 0, searched_files, results);
+ EXPECT_EQ(0u, num_results);
+ EXPECT_EQ(0u, results.GetSize());
+}
diff --git a/unittests/Utility/CMakeLists.txt b/unittests/Utility/CMakeLists.txt
index 30936acce9dce..99677a47d7cc1 100644
--- a/unittests/Utility/CMakeLists.txt
+++ b/unittests/Utility/CMakeLists.txt
@@ -1,5 +1,8 @@
add_lldb_unittest(UtilityTests
+ ModuleCacheTest.cpp
StringExtractorTest.cpp
TaskPoolTest.cpp
UriParserTest.cpp
)
+
+add_unittest_inputs(UtilityTests TestModule.so)
diff --git a/unittests/Utility/Inputs/TestModule.c b/unittests/Utility/Inputs/TestModule.c
new file mode 100644
index 0000000000000..12374e1f7c65a
--- /dev/null
+++ b/unittests/Utility/Inputs/TestModule.c
@@ -0,0 +1,10 @@
+// Compile with $CC -nostdlib -shared TestModule.c -o TestModule.so
+// The actual contents of the test module is not important here. I am using this because it
+// produces an extremely tiny (but still perfectly valid) module.
+
+void
+boom(void)
+{
+ char *BOOM;
+ *BOOM = 47;
+}
diff --git a/unittests/Utility/Inputs/TestModule.so b/unittests/Utility/Inputs/TestModule.so
new file mode 100644
index 0000000000000..9e9bf0b6e17ea
--- /dev/null
+++ b/unittests/Utility/Inputs/TestModule.so
Binary files differ
diff --git a/unittests/Utility/ModuleCacheTest.cpp b/unittests/Utility/ModuleCacheTest.cpp
new file mode 100644
index 0000000000000..53bfc882f2326
--- /dev/null
+++ b/unittests/Utility/ModuleCacheTest.cpp
@@ -0,0 +1,179 @@
+#include "gtest/gtest.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Utility/ModuleCache.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+extern const char *TestMainArgv0;
+
+using namespace lldb_private;
+using namespace lldb;
+
+namespace
+{
+
+class ModuleCacheTest : public testing::Test
+{
+public:
+ static void
+ SetUpTestCase();
+
+ static void
+ TearDownTestCase();
+
+protected:
+ static FileSpec s_cache_dir;
+ static llvm::SmallString<128> s_test_executable;
+
+ void
+ TryGetAndPut(const FileSpec &cache_dir, const char *hostname, bool expect_download);
+};
+}
+
+FileSpec ModuleCacheTest::s_cache_dir;
+llvm::SmallString<128> ModuleCacheTest::s_test_executable;
+
+static const char dummy_hostname[] = "dummy_hostname";
+static const char dummy_remote_dir[] = "bin";
+static const char module_name[] = "TestModule.so";
+static const char module_uuid[] = "F4E7E991-9B61-6AD4-0073-561AC3D9FA10-C043A476";
+static const uint32_t uuid_bytes = 20;
+static const size_t module_size = 5602;
+
+static FileSpec
+GetDummyRemotePath()
+{
+ FileSpec fs("/", false, FileSpec::ePathSyntaxPosix);
+ fs.AppendPathComponent(dummy_remote_dir);
+ fs.AppendPathComponent(module_name);
+ return fs;
+}
+
+static FileSpec
+GetUuidView(FileSpec spec)
+{
+ spec.AppendPathComponent(".cache");
+ spec.AppendPathComponent(module_uuid);
+ spec.AppendPathComponent(module_name);
+ return spec;
+}
+
+static FileSpec
+GetSysrootView(FileSpec spec, const char *hostname)
+{
+ spec.AppendPathComponent(hostname);
+ spec.AppendPathComponent(dummy_remote_dir);
+ spec.AppendPathComponent(module_name);
+ return spec;
+}
+
+void
+ModuleCacheTest::SetUpTestCase()
+{
+ HostInfo::Initialize();
+ ObjectFileELF::Initialize();
+
+ FileSpec tmpdir_spec;
+ HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, s_cache_dir);
+
+ llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0);
+ s_test_executable = exe_folder;
+ llvm::sys::path::append(s_test_executable, "Inputs", module_name);
+}
+
+void
+ModuleCacheTest::TearDownTestCase()
+{
+ ObjectFileELF::Terminate();
+ HostInfo::Terminate();
+}
+
+static void
+VerifyDiskState(const FileSpec &cache_dir, const char *hostname)
+{
+ FileSpec uuid_view = GetUuidView(cache_dir);
+ EXPECT_TRUE(uuid_view.Exists()) << "uuid_view is: " << uuid_view.GetCString();
+ EXPECT_EQ(module_size, uuid_view.GetByteSize());
+
+ FileSpec sysroot_view = GetSysrootView(cache_dir, hostname);
+ EXPECT_TRUE(sysroot_view.Exists()) << "sysroot_view is: " << sysroot_view.GetCString();
+ EXPECT_EQ(module_size, sysroot_view.GetByteSize());
+}
+
+void
+ModuleCacheTest::TryGetAndPut(const FileSpec &cache_dir, const char *hostname, bool expect_download)
+{
+ ModuleCache mc;
+ ModuleSpec module_spec;
+ module_spec.GetFileSpec() = GetDummyRemotePath();
+ module_spec.GetUUID().SetFromCString(module_uuid, uuid_bytes);
+ module_spec.SetObjectSize(module_size);
+ ModuleSP module_sp;
+ bool did_create;
+ bool download_called = false;
+
+ Error error = mc.GetAndPut(
+ cache_dir, hostname, module_spec,
+ [this, &download_called](const ModuleSpec &module_spec, const FileSpec &tmp_download_file_spec) {
+ download_called = true;
+ EXPECT_STREQ(GetDummyRemotePath().GetCString(), module_spec.GetFileSpec().GetCString());
+ std::error_code ec = llvm::sys::fs::copy_file(s_test_executable, tmp_download_file_spec.GetCString());
+ EXPECT_FALSE(ec);
+ return Error();
+ },
+ [](const ModuleSP &module_sp, const FileSpec &tmp_download_file_spec) { return Error("Not supported."); },
+ module_sp, &did_create);
+ EXPECT_EQ(expect_download, download_called);
+
+ EXPECT_TRUE(error.Success()) << "Error was: " << error.AsCString();
+ EXPECT_TRUE(did_create);
+ ASSERT_TRUE(bool(module_sp));
+
+ SymbolContextList sc_list;
+ EXPECT_EQ(1u, module_sp->FindFunctionSymbols(ConstString("boom"), eFunctionNameTypeFull, sc_list));
+ EXPECT_STREQ(GetDummyRemotePath().GetCString(), module_sp->GetPlatformFileSpec().GetCString());
+ EXPECT_STREQ(module_uuid, module_sp->GetUUID().GetAsString().c_str());
+}
+
+TEST_F(ModuleCacheTest, GetAndPut)
+{
+ FileSpec test_cache_dir = s_cache_dir;
+ test_cache_dir.AppendPathComponent("GetAndPut");
+
+ const bool expect_download = true;
+ TryGetAndPut(test_cache_dir, dummy_hostname, expect_download);
+ VerifyDiskState(test_cache_dir, dummy_hostname);
+}
+
+TEST_F(ModuleCacheTest, GetAndPutUuidExists)
+{
+ FileSpec test_cache_dir = s_cache_dir;
+ test_cache_dir.AppendPathComponent("GetAndPutUuidExists");
+
+ FileSpec uuid_view = GetUuidView(test_cache_dir);
+ std::error_code ec = llvm::sys::fs::create_directories(uuid_view.GetDirectory().GetCString());
+ ASSERT_FALSE(ec);
+ ec = llvm::sys::fs::copy_file(s_test_executable, uuid_view.GetCString());
+ ASSERT_FALSE(ec);
+
+ const bool expect_download = false;
+ TryGetAndPut(test_cache_dir, dummy_hostname, expect_download);
+ VerifyDiskState(test_cache_dir, dummy_hostname);
+}
+
+TEST_F(ModuleCacheTest, GetAndPutStrangeHostname)
+{
+ FileSpec test_cache_dir = s_cache_dir;
+ test_cache_dir.AppendPathComponent("GetAndPutStrangeHostname");
+
+ const bool expect_download = true;
+ TryGetAndPut(test_cache_dir, "tab\tcolon:asterisk*", expect_download);
+ VerifyDiskState(test_cache_dir, "tab_colon_asterisk_");
+}