summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Expression/ExpressionSourceCode.h1
-rw-r--r--lldb/include/lldb/Target/Platform.h15
-rw-r--r--lldb/include/lldb/Target/Target.h2
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile5
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py56
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp7
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile5
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestStdModuleWithConflicts.py36
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp10
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile5
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestMissingStdModule.py40
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp5
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/Makefile10
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/TestStdModuleSysroot.py34
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/main.cpp6
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/algorithm7
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/module.modulemap3
-rw-r--r--lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/libc_header.h1
-rw-r--r--lldb/packages/Python/lldbsuite/test/make/Makefile.rules13
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp26
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h579
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp164
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h9
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp35
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h17
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp78
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h11
-rw-r--r--lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp19
-rw-r--r--lldb/source/Plugins/Platform/Linux/PlatformLinux.h3
-rw-r--r--lldb/source/Target/Target.cpp10
31 files changed, 1164 insertions, 49 deletions
diff --git a/lldb/include/lldb/Expression/ExpressionSourceCode.h b/lldb/include/lldb/Expression/ExpressionSourceCode.h
index 1226ead1deb..d0d01b5f9b5 100644
--- a/lldb/include/lldb/Expression/ExpressionSourceCode.h
+++ b/lldb/include/lldb/Expression/ExpressionSourceCode.h
@@ -10,6 +10,7 @@
#define liblldb_ExpressionSourceCode_h
#include "lldb/lldb-enumerations.h"
+#include "llvm/ADT/ArrayRef.h"
#include <string>
diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h
index ccbb19966b1..ceecc7793b8 100644
--- a/lldb/include/lldb/Target/Platform.h
+++ b/lldb/include/lldb/Target/Platform.h
@@ -281,6 +281,21 @@ public:
virtual bool SetRemoteWorkingDirectory(const FileSpec &working_dir);
+ //------------------------------------------------------------------
+ /// Retrieve the system include directories on this platform for the
+ /// given language.
+ ///
+ /// \param[in] lang
+ /// The language for which the include directories should be queried.
+ ///
+ /// \param[out] directories
+ /// The include directories for this system.
+ //------------------------------------------------------------------
+ virtual std::vector<std::string>
+ GetSystemIncludeDirectories(lldb::LanguageType lang) {
+ return {};
+ }
+
virtual UserIDResolver &GetUserIDResolver() = 0;
//------------------------------------------------------------------
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 8201deb19bf..715017fce4f 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -129,6 +129,8 @@ public:
bool GetEnableAutoImportClangModules() const;
+ bool GetEnableImportStdModule() const;
+
bool GetEnableAutoApplyFixIts() const;
bool GetEnableNotifyAboutFixIts() const;
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile
new file mode 100644
index 00000000000..01718d86aa7
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+USE_LIBCPP := 1
+CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS)
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py
new file mode 100644
index 00000000000..2b87c2e5711
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py
@@ -0,0 +1,56 @@
+"""
+Test importing the 'std' C++ module and evaluate expressions with it.
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ImportStdModule(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ # FIXME: This should work on more setups, so remove these
+ # skipIf's in the future.
+ @add_test_categories(["libc++"])
+ @skipIf(compiler=no_match("clang"))
+ @skipIf(oslist=no_match(["linux"]))
+ @skipIf(debug_info=no_match(["dwarf"]))
+ def test(self):
+ self.build()
+
+ lldbutil.run_to_source_breakpoint(self,
+ "// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
+
+ # Activate importing of std module.
+ self.runCmd("settings set target.import-std-module true")
+ # Calling some normal std functions that return non-template types.
+ self.expect("expr std::abs(-42)", substrs=['(int) $0 = 42'])
+ self.expect("expr std::div(2, 1).quot", substrs=['(int) $1 = 2'])
+ # Using types from std.
+ self.expect("expr (std::size_t)33U", substrs=['(size_t) $2 = 33'])
+ # Calling templated functions that return non-template types.
+ self.expect("expr char a = 'b'; char b = 'a'; std::swap(a, b); a",
+ substrs=["(char) $3 = 'a'"])
+
+ # FIXME: This should work on more setups, so remove these
+ # skipIf's in the future.
+ @add_test_categories(["libc++"])
+ @skipIf(compiler=no_match("clang"))
+ @skipIf(oslist=no_match(["linux"]))
+ @skipIf(debug_info=no_match(["dwarf"]))
+ def test_non_cpp_language(self):
+ self.build()
+
+ lldbutil.run_to_source_breakpoint(self,
+ "// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
+
+ # Activate importing of std module.
+ self.runCmd("settings set target.import-std-module true")
+ # These languages don't support C++ modules, so they shouldn't
+ # be able to evaluate the expression.
+ self.expect("expr -l C -- std::abs(-42)", error=True)
+ self.expect("expr -l C99 -- std::abs(-42)", error=True)
+ self.expect("expr -l C11 -- std::abs(-42)", error=True)
+ self.expect("expr -l ObjC -- std::abs(-42)", error=True)
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp
new file mode 100644
index 00000000000..2f6d078daa3
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp
@@ -0,0 +1,7 @@
+// We need to import any std module. It doesn't matter which one.
+#include <iostream>
+
+int main(int argc, char **argv) {
+ std::cout << "Test" << std::endl;
+ return 0; // Set break point at this line.
+}
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile
new file mode 100644
index 00000000000..01718d86aa7
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+USE_LIBCPP := 1
+CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS)
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestStdModuleWithConflicts.py b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestStdModuleWithConflicts.py
new file mode 100644
index 00000000000..8be474e39ce
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestStdModuleWithConflicts.py
@@ -0,0 +1,36 @@
+"""
+Test importing the 'std' C++ module and check if we can handle
+prioritizing the conflicting functions from debug info and std
+module.
+
+See also import-std-module/basic/TestImportStdModule.py for
+the same test on a 'clean' code base without conflicts.
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestImportStdModuleConflicts(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ # FIXME: This should work on more setups, so remove these
+ # skipIf's in the future.
+ @add_test_categories(["libc++"])
+ @skipIf(compiler=no_match("clang"))
+ @skipIf(oslist=no_match(["linux"]))
+ @skipIf(debug_info=no_match(["dwarf"]))
+ def test(self):
+ self.build()
+
+ lldbutil.run_to_source_breakpoint(self,
+ "// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
+
+ self.runCmd("settings set target.import-std-module true")
+ self.expect("expr std::abs(-42)", substrs=['(int) $0 = 42'])
+ self.expect("expr std::div(2, 1).quot", substrs=['(int) $1 = 2'])
+ self.expect("expr (std::size_t)33U", substrs=['(size_t) $2 = 33'])
+ self.expect("expr char a = 'b'; char b = 'a'; std::swap(a, b); a",
+ substrs=["(char) $3 = 'a'"])
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp
new file mode 100644
index 00000000000..e49b862a36c
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp
@@ -0,0 +1,10 @@
+#include <cstdlib>
+#include <utility>
+
+int main(int argc, char **argv) {
+ std::size_t f = argc;
+ f = std::abs(argc);
+ f = std::div(argc * 2, argc).quot;
+ std::swap(f, f);
+ return f; // Set break point at this line.
+}
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile
new file mode 100644
index 00000000000..01718d86aa7
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+USE_LIBCPP := 1
+CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS)
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestMissingStdModule.py b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestMissingStdModule.py
new file mode 100644
index 00000000000..f4d3d1fd492
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestMissingStdModule.py
@@ -0,0 +1,40 @@
+"""
+Test that importing the std module on a compile unit
+that doesn't use the std module will not break LLDB.
+
+It's not really specified at the moment what kind of
+error we should report back to the user in this
+situation. Currently Clang will just complain that
+the std module doesn't exist or can't be loaded.
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class STLTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ # FIXME: This should work on more setups, so remove these
+ # skipIf's in the future.
+ @add_test_categories(["libc++"])
+ @skipIf(compiler=no_match("clang"))
+ @skipIf(oslist=no_match(["linux"]))
+ @skipIf(debug_info=no_match(["dwarf"]))
+ def test(self):
+ self.build()
+
+ lldbutil.run_to_source_breakpoint(self,
+ "// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
+
+ # Activate importing of std module.
+ self.runCmd("settings set target.import-std-module true")
+
+ # Run some commands that should all fail without our std module.
+ self.expect("expr std::abs(-42)", error=True)
+ self.expect("expr std::div(2, 1).quot", error=True)
+ self.expect("expr (std::size_t)33U", error=True)
+ self.expect("expr char a = 'b'; char b = 'a'; std::swap(a, b); a",
+ error=True)
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp
new file mode 100644
index 00000000000..c93e9d0ec8a
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp
@@ -0,0 +1,5 @@
+// We don't import any std module here.
+
+int main(int argc, char **argv) {
+ return 0; // Set break point at this line.
+}
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/Makefile b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/Makefile
new file mode 100644
index 00000000000..e04d73ea487
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/Makefile
@@ -0,0 +1,10 @@
+LEVEL = ../../../make
+# We don't have any standard include directories, so we can't
+# parse the test_common.h header we usually inject as it includes
+# system headers.
+NO_TEST_COMMON_H := 1
+
+CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS)
+CXXFLAGS += -I $(SRCDIR)/root/usr/include/c++/include/ -I $(SRCDIR)/root/usr/include/ -nostdinc -nostdinc++ -nostdlib++
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/TestStdModuleSysroot.py b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/TestStdModuleSysroot.py
new file mode 100644
index 00000000000..dfd90e80e45
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/TestStdModuleSysroot.py
@@ -0,0 +1,34 @@
+"""
+Test that we respect the sysroot when building the std module.
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import os
+
+class ImportStdModule(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ # FIXME: This should work on more setups, so remove these
+ # skipIf's in the future.
+ @skipIf(compiler=no_match("clang"))
+ @skipIf(oslist=no_match(["linux"]))
+ @skipIf(debug_info=no_match(["dwarf"]))
+ def test(self):
+ self.build()
+
+ sysroot = os.path.join(os.getcwd(), "root")
+
+ # Set the sysroot.
+ self.runCmd("platform select --sysroot '" + sysroot + "' host", CURRENT_EXECUTABLE_SET)
+
+ lldbutil.run_to_source_breakpoint(self,
+ "// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
+
+ self.runCmd("settings set target.import-std-module true")
+
+ # Call our custom function in our sysroot std module.
+ # If this gives us the correct result, then we used the sysroot.
+ self.expect("expr std::myabs(-42)", substrs=['(int) $0 = 42'])
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/main.cpp b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/main.cpp
new file mode 100644
index 00000000000..2fbc76b9a76
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/main.cpp
@@ -0,0 +1,6 @@
+#include <algorithm>
+
+int main(int argc, char **argv) {
+ libc_struct s;
+ return 0; // Set break point at this line.
+}
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/algorithm b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/algorithm
new file mode 100644
index 00000000000..e8cbcca8e84
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/algorithm
@@ -0,0 +1,7 @@
+#include "libc_header.h"
+
+namespace std {
+ int myabs(int i) {
+ return i < 0 ? -i : i;
+ }
+}
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/module.modulemap b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/module.modulemap
new file mode 100644
index 00000000000..0eb48492a65
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/module.modulemap
@@ -0,0 +1,3 @@
+module std {
+ module "algorithm" { header "algorithm" export * }
+}
diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/libc_header.h b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/libc_header.h
new file mode 100644
index 00000000000..47525c9db34
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/libc_header.h
@@ -0,0 +1 @@
+struct libc_struct {};
diff --git a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules
index fc72bceb195..9cf5d9ddba2 100644
--- a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules
+++ b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules
@@ -272,7 +272,12 @@ else
CFLAGS += $(ARCHFLAG)$(ARCH) $(FRAMEWORK_INCLUDES) -I$(LLDB_BASE_DIR)include
endif
-CFLAGS += -I$(SRCDIR) -include $(THIS_FILE_DIR)test_common.h -I$(THIS_FILE_DIR)
+CFLAGS += -I$(SRCDIR) -I$(THIS_FILE_DIR)
+
+ifndef NO_TEST_COMMON_H
+ CFLAGS += -include $(THIS_FILE_DIR)test_common.h
+endif
+
CFLAGS += $(NO_LIMIT_DEBUG_INFO_FLAGS) $(ARCH_CFLAGS) $(CFLAGS_EXTRAS)
# If the OS is Windows, we need to pass -gdwarf to clang, otherwise it will build
@@ -300,7 +305,11 @@ CLANG_MODULE_CACHE_DIR := $(BUILDDIR)/module-cache
$(warning failed to set the shared clang module cache dir)
endif
-MANDATORY_MODULE_BUILD_CFLAGS := -fmodules -gmodules -fmodules-cache-path=$(CLANG_MODULE_CACHE_DIR)
+MODULE_BASE_FLAGS := -fmodules -gmodules -fmodules-cache-path=$(CLANG_MODULE_CACHE_DIR)
+MANDATORY_MODULE_BUILD_CFLAGS := $(MODULE_BASE_FLAGS) -gmodules
+# Build flags for building with C++ modules.
+# -glldb is necessary for emitting information about what modules were imported.
+MANDATORY_CXXMODULE_BUILD_CFLAGS := $(MODULE_BASE_FLAGS) -fcxx-modules -glldb
ifeq "$(OS)" "Darwin"
MANDATORY_MODULE_BUILD_CFLAGS += -fcxx-modules
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp
new file mode 100644
index 00000000000..bbdf4e31c5a
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp
@@ -0,0 +1,26 @@
+//===-- ASTUtils.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 "ASTUtils.h"
+
+lldb_private::ExternalASTSourceWrapper::~ExternalASTSourceWrapper() {}
+
+void lldb_private::ExternalASTSourceWrapper::PrintStats() {
+ m_Source->PrintStats();
+}
+
+lldb_private::ASTConsumerForwarder::~ASTConsumerForwarder() {}
+
+void lldb_private::ASTConsumerForwarder::PrintStats() { m_c->PrintStats(); }
+
+lldb_private::SemaSourceWithPriorities::~SemaSourceWithPriorities() {}
+
+void lldb_private::SemaSourceWithPriorities::PrintStats() {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->PrintStats();
+}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h
new file mode 100644
index 00000000000..d429e8c3855
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h
@@ -0,0 +1,579 @@
+//===-- ASTUtils.h ----------------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ASTUtils_h_
+#define liblldb_ASTUtils_h_
+
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/MultiplexExternalSemaSource.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaConsumer.h"
+
+namespace lldb_private {
+
+/// Wraps an ExternalASTSource into an ExternalSemaSource. Doesn't take
+/// ownership of the provided source.
+class ExternalASTSourceWrapper : public clang::ExternalSemaSource {
+ ExternalASTSource *m_Source;
+
+public:
+ ExternalASTSourceWrapper(ExternalASTSource *Source) : m_Source(Source) {
+ assert(m_Source && "Can't wrap nullptr ExternalASTSource");
+ }
+
+ ~ExternalASTSourceWrapper() override;
+
+ clang::Decl *GetExternalDecl(uint32_t ID) override {
+ return m_Source->GetExternalDecl(ID);
+ }
+
+ clang::Selector GetExternalSelector(uint32_t ID) override {
+ return m_Source->GetExternalSelector(ID);
+ }
+
+ uint32_t GetNumExternalSelectors() override {
+ return m_Source->GetNumExternalSelectors();
+ }
+
+ clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override {
+ return m_Source->GetExternalDeclStmt(Offset);
+ }
+
+ clang::CXXCtorInitializer **
+ GetExternalCXXCtorInitializers(uint64_t Offset) override {
+ return m_Source->GetExternalCXXCtorInitializers(Offset);
+ }
+
+ clang::CXXBaseSpecifier *
+ GetExternalCXXBaseSpecifiers(uint64_t Offset) override {
+ return m_Source->GetExternalCXXBaseSpecifiers(Offset);
+ }
+
+ void updateOutOfDateIdentifier(clang::IdentifierInfo &II) override {
+ m_Source->updateOutOfDateIdentifier(II);
+ }
+
+ bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
+ clang::DeclarationName Name) override {
+ return m_Source->FindExternalVisibleDeclsByName(DC, Name);
+ }
+
+ void completeVisibleDeclsMap(const clang::DeclContext *DC) override {
+ m_Source->completeVisibleDeclsMap(DC);
+ }
+
+ clang::Module *getModule(unsigned ID) override {
+ return m_Source->getModule(ID);
+ }
+
+ llvm::Optional<ASTSourceDescriptor>
+ getSourceDescriptor(unsigned ID) override {
+ return m_Source->getSourceDescriptor(ID);
+ }
+
+ ExtKind hasExternalDefinitions(const clang::Decl *D) override {
+ return m_Source->hasExternalDefinitions(D);
+ }
+
+ void FindExternalLexicalDecls(
+ const clang::DeclContext *DC,
+ llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+ llvm::SmallVectorImpl<clang::Decl *> &Result) override {
+ m_Source->FindExternalLexicalDecls(DC, IsKindWeWant, Result);
+ }
+
+ void
+ FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length,
+ llvm::SmallVectorImpl<clang::Decl *> &Decls) override {
+ m_Source->FindFileRegionDecls(File, Offset, Length, Decls);
+ }
+
+ void CompleteRedeclChain(const clang::Decl *D) override {
+ m_Source->CompleteRedeclChain(D);
+ }
+
+ void CompleteType(clang::TagDecl *Tag) override {
+ m_Source->CompleteType(Tag);
+ }
+
+ void CompleteType(clang::ObjCInterfaceDecl *Class) override {
+ m_Source->CompleteType(Class);
+ }
+
+ void ReadComments() override { m_Source->ReadComments(); }
+
+ void StartedDeserializing() override { m_Source->StartedDeserializing(); }
+
+ void FinishedDeserializing() override { m_Source->FinishedDeserializing(); }
+
+ void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
+ m_Source->StartTranslationUnit(Consumer);
+ }
+
+ void PrintStats() override;
+
+ bool layoutRecordType(
+ const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &BaseOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &VirtualBaseOffsets) override {
+ return m_Source->layoutRecordType(Record, Size, Alignment, FieldOffsets,
+ BaseOffsets, VirtualBaseOffsets);
+ }
+};
+
+/// Wraps an ASTConsumer into an SemaConsumer. Doesn't take ownership of the
+/// provided consumer. If the provided ASTConsumer is also a SemaConsumer,
+/// the wrapper will also forward SemaConsumer functions.
+class ASTConsumerForwarder : public clang::SemaConsumer {
+ clang::ASTConsumer *m_c;
+ clang::SemaConsumer *m_sc;
+
+public:
+ ASTConsumerForwarder(clang::ASTConsumer *c) : m_c(c) {
+ m_sc = llvm::dyn_cast<clang::SemaConsumer>(m_c);
+ }
+
+ ~ASTConsumerForwarder() override;
+
+ void Initialize(clang::ASTContext &Context) override {
+ m_c->Initialize(Context);
+ }
+
+ bool HandleTopLevelDecl(clang::DeclGroupRef D) override {
+ return m_c->HandleTopLevelDecl(D);
+ }
+
+ void HandleInlineFunctionDefinition(clang::FunctionDecl *D) override {
+ m_c->HandleInlineFunctionDefinition(D);
+ }
+
+ void HandleInterestingDecl(clang::DeclGroupRef D) override {
+ m_c->HandleInterestingDecl(D);
+ }
+
+ void HandleTranslationUnit(clang::ASTContext &Ctx) override {
+ m_c->HandleTranslationUnit(Ctx);
+ }
+
+ void HandleTagDeclDefinition(clang::TagDecl *D) override {
+ m_c->HandleTagDeclDefinition(D);
+ }
+
+ void HandleTagDeclRequiredDefinition(const clang::TagDecl *D) override {
+ m_c->HandleTagDeclRequiredDefinition(D);
+ }
+
+ void HandleCXXImplicitFunctionInstantiation(clang::FunctionDecl *D) override {
+ m_c->HandleCXXImplicitFunctionInstantiation(D);
+ }
+
+ void HandleTopLevelDeclInObjCContainer(clang::DeclGroupRef D) override {
+ m_c->HandleTopLevelDeclInObjCContainer(D);
+ }
+
+ void HandleImplicitImportDecl(clang::ImportDecl *D) override {
+ m_c->HandleImplicitImportDecl(D);
+ }
+
+ void CompleteTentativeDefinition(clang::VarDecl *D) override {
+ m_c->CompleteTentativeDefinition(D);
+ }
+
+ void AssignInheritanceModel(clang::CXXRecordDecl *RD) override {
+ m_c->AssignInheritanceModel(RD);
+ }
+
+ void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *D) override {
+ m_c->HandleCXXStaticMemberVarInstantiation(D);
+ }
+
+ void HandleVTable(clang::CXXRecordDecl *RD) override {
+ m_c->HandleVTable(RD);
+ }
+
+ clang::ASTMutationListener *GetASTMutationListener() override {
+ return m_c->GetASTMutationListener();
+ }
+
+ clang::ASTDeserializationListener *GetASTDeserializationListener() override {
+ return m_c->GetASTDeserializationListener();
+ }
+
+ void PrintStats() override;
+
+ void InitializeSema(clang::Sema &S) override {
+ if (m_sc)
+ m_sc->InitializeSema(S);
+ }
+
+ /// Inform the semantic consumer that Sema is no longer available.
+ void ForgetSema() override {
+ if (m_sc)
+ m_sc->ForgetSema();
+ }
+
+ bool shouldSkipFunctionBody(clang::Decl *D) override {
+ return m_c->shouldSkipFunctionBody(D);
+ }
+};
+
+/// A ExternalSemaSource multiplexer that prioritizes its sources.
+///
+/// This ExternalSemaSource will forward all requests to its attached sources.
+/// However, unlike a normal multiplexer it will not forward a request to all
+/// sources, but instead give priority to certain sources. If a source with a
+/// higher priority can fulfill a request, all sources with a lower priority
+/// will not receive the request.
+///
+/// This class is mostly use to multiplex between sources of different
+/// 'quality', e.g. a C++ modules and debug information. The C++ module will
+/// provide more accurate replies to the requests, but might not be able to
+/// answer all requests. The debug information will be used as a fallback then
+/// to provide information that is not in the C++ module.
+class SemaSourceWithPriorities : public clang::ExternalSemaSource {
+
+private:
+ /// The sources ordered in decreasing priority.
+ llvm::SmallVector<clang::ExternalSemaSource *, 2> Sources;
+
+public:
+ /// Construct a SemaSourceWithPriorities with a 'high quality' source that
+ /// has the higher priority and a 'low quality' source that will be used
+ /// as a fallback.
+ SemaSourceWithPriorities(clang::ExternalSemaSource &high_quality_source,
+ clang::ExternalSemaSource &low_quality_source) {
+ Sources.push_back(&high_quality_source);
+ Sources.push_back(&low_quality_source);
+ }
+
+ ~SemaSourceWithPriorities() override;
+
+ void addSource(clang::ExternalSemaSource &source) {
+ Sources.push_back(&source);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // ExternalASTSource.
+ //===--------------------------------------------------------------------===//
+
+ clang::Decl *GetExternalDecl(uint32_t ID) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (clang::Decl *Result = Sources[i]->GetExternalDecl(ID))
+ return Result;
+ return nullptr;
+ }
+
+ void CompleteRedeclChain(const clang::Decl *D) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->CompleteRedeclChain(D);
+ }
+
+ clang::Selector GetExternalSelector(uint32_t ID) override {
+ clang::Selector Sel;
+ for (size_t i = 0; i < Sources.size(); ++i) {
+ Sel = Sources[i]->GetExternalSelector(ID);
+ if (!Sel.isNull())
+ return Sel;
+ }
+ return Sel;
+ }
+
+ uint32_t GetNumExternalSelectors() override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (uint32_t total = Sources[i]->GetNumExternalSelectors())
+ return total;
+ return 0;
+ }
+
+ clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (clang::Stmt *Result = Sources[i]->GetExternalDeclStmt(Offset))
+ return Result;
+ return nullptr;
+ }
+
+ clang::CXXBaseSpecifier *
+ GetExternalCXXBaseSpecifiers(uint64_t Offset) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (clang::CXXBaseSpecifier *R =
+ Sources[i]->GetExternalCXXBaseSpecifiers(Offset))
+ return R;
+ return nullptr;
+ }
+
+ clang::CXXCtorInitializer **
+ GetExternalCXXCtorInitializers(uint64_t Offset) override {
+ for (auto *S : Sources)
+ if (auto *R = S->GetExternalCXXCtorInitializers(Offset))
+ return R;
+ return nullptr;
+ }
+
+ ExtKind hasExternalDefinitions(const clang::Decl *D) override {
+ for (const auto &S : Sources)
+ if (auto EK = S->hasExternalDefinitions(D))
+ if (EK != EK_ReplyHazy)
+ return EK;
+ return EK_ReplyHazy;
+ }
+
+ bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
+ clang::DeclarationName Name) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (Sources[i]->FindExternalVisibleDeclsByName(DC, Name))
+ return true;
+ return false;
+ }
+
+ void completeVisibleDeclsMap(const clang::DeclContext *DC) override {
+ // FIXME: Only one source should be able to complete the decls map.
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->completeVisibleDeclsMap(DC);
+ }
+
+ void FindExternalLexicalDecls(
+ const clang::DeclContext *DC,
+ llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+ llvm::SmallVectorImpl<clang::Decl *> &Result) override {
+ for (size_t i = 0; i < Sources.size(); ++i) {
+ Sources[i]->FindExternalLexicalDecls(DC, IsKindWeWant, Result);
+ if (!Result.empty())
+ return;
+ }
+ }
+
+ void
+ FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length,
+ llvm::SmallVectorImpl<clang::Decl *> &Decls) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->FindFileRegionDecls(File, Offset, Length, Decls);
+ }
+
+ void CompleteType(clang::TagDecl *Tag) override {
+ while (!Tag->isCompleteDefinition())
+ for (size_t i = 0; i < Sources.size(); ++i) {
+ // FIXME: We are technically supposed to loop here too until
+ // Tag->isCompleteDefinition() is true, but if our low quality source
+ // is failing to complete the tag this code will deadlock.
+ Sources[i]->CompleteType(Tag);
+ if (Tag->isCompleteDefinition())
+ break;
+ }
+ }
+
+ void CompleteType(clang::ObjCInterfaceDecl *Class) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->CompleteType(Class);
+ }
+
+ void ReadComments() override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadComments();
+ }
+
+ void StartedDeserializing() override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->StartedDeserializing();
+ }
+
+ void FinishedDeserializing() override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->FinishedDeserializing();
+ }
+
+ void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->StartTranslationUnit(Consumer);
+ }
+
+ void PrintStats() override;
+
+ clang::Module *getModule(unsigned ID) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (auto M = Sources[i]->getModule(ID))
+ return M;
+ return nullptr;
+ }
+
+ bool DeclIsFromPCHWithObjectFile(const clang::Decl *D) override {
+ for (auto *S : Sources)
+ if (S->DeclIsFromPCHWithObjectFile(D))
+ return true;
+ return false;
+ }
+
+ bool layoutRecordType(
+ const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &BaseOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &VirtualBaseOffsets) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (Sources[i]->layoutRecordType(Record, Size, Alignment, FieldOffsets,
+ BaseOffsets, VirtualBaseOffsets))
+ return true;
+ return false;
+ }
+
+ void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {
+ for (auto &Source : Sources)
+ Source->getMemoryBufferSizes(sizes);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // ExternalSemaSource.
+ //===--------------------------------------------------------------------===//
+
+ void InitializeSema(clang::Sema &S) override {
+ for (auto &Source : Sources)
+ Source->InitializeSema(S);
+ }
+
+ void ForgetSema() override {
+ for (auto &Source : Sources)
+ Source->ForgetSema();
+ }
+
+ void ReadMethodPool(clang::Selector Sel) override {
+ for (auto &Source : Sources)
+ Source->ReadMethodPool(Sel);
+ }
+
+ void updateOutOfDateSelector(clang::Selector Sel) override {
+ for (auto &Source : Sources)
+ Source->updateOutOfDateSelector(Sel);
+ }
+
+ void ReadKnownNamespaces(
+ llvm::SmallVectorImpl<clang::NamespaceDecl *> &Namespaces) override {
+ for (auto &Source : Sources)
+ Source->ReadKnownNamespaces(Namespaces);
+ }
+
+ void ReadUndefinedButUsed(
+ llvm::MapVector<clang::NamedDecl *, clang::SourceLocation> &Undefined)
+ override {
+ for (auto &Source : Sources)
+ Source->ReadUndefinedButUsed(Undefined);
+ }
+
+ void ReadMismatchingDeleteExpressions(
+ llvm::MapVector<clang::FieldDecl *,
+ llvm::SmallVector<std::pair<clang::SourceLocation, bool>,
+ 4>> &Exprs) override {
+ for (auto &Source : Sources)
+ Source->ReadMismatchingDeleteExpressions(Exprs);
+ }
+
+ bool LookupUnqualified(clang::LookupResult &R, clang::Scope *S) override {
+ for (auto &Source : Sources) {
+ Source->LookupUnqualified(R, S);
+ if (!R.empty())
+ break;
+ }
+
+ return !R.empty();
+ }
+
+ void ReadTentativeDefinitions(
+ llvm::SmallVectorImpl<clang::VarDecl *> &Defs) override {
+ for (auto &Source : Sources)
+ Source->ReadTentativeDefinitions(Defs);
+ }
+
+ void ReadUnusedFileScopedDecls(
+ llvm::SmallVectorImpl<const clang::DeclaratorDecl *> &Decls) override {
+ for (auto &Source : Sources)
+ Source->ReadUnusedFileScopedDecls(Decls);
+ }
+
+ void ReadDelegatingConstructors(
+ llvm::SmallVectorImpl<clang::CXXConstructorDecl *> &Decls) override {
+ for (auto &Source : Sources)
+ Source->ReadDelegatingConstructors(Decls);
+ }
+
+ void ReadExtVectorDecls(
+ llvm::SmallVectorImpl<clang::TypedefNameDecl *> &Decls) override {
+ for (auto &Source : Sources)
+ Source->ReadExtVectorDecls(Decls);
+ }
+
+ void ReadUnusedLocalTypedefNameCandidates(
+ llvm::SmallSetVector<const clang::TypedefNameDecl *, 4> &Decls) override {
+ for (auto &Source : Sources)
+ Source->ReadUnusedLocalTypedefNameCandidates(Decls);
+ }
+
+ void ReadReferencedSelectors(
+ llvm::SmallVectorImpl<std::pair<clang::Selector, clang::SourceLocation>>
+ &Sels) override {
+ for (auto &Source : Sources)
+ Source->ReadReferencedSelectors(Sels);
+ }
+
+ void ReadWeakUndeclaredIdentifiers(
+ llvm::SmallVectorImpl<std::pair<clang::IdentifierInfo *, clang::WeakInfo>>
+ &WI) override {
+ for (auto &Source : Sources)
+ Source->ReadWeakUndeclaredIdentifiers(WI);
+ }
+
+ void ReadUsedVTables(
+ llvm::SmallVectorImpl<clang::ExternalVTableUse> &VTables) override {
+ for (auto &Source : Sources)
+ Source->ReadUsedVTables(VTables);
+ }
+
+ void ReadPendingInstantiations(
+ llvm::SmallVectorImpl<
+ std::pair<clang::ValueDecl *, clang::SourceLocation>> &Pending)
+ override {
+ for (auto &Source : Sources)
+ Source->ReadPendingInstantiations(Pending);
+ }
+
+ void ReadLateParsedTemplates(
+ llvm::MapVector<const clang::FunctionDecl *,
+ std::unique_ptr<clang::LateParsedTemplate>> &LPTMap)
+ override {
+ for (auto &Source : Sources)
+ Source->ReadLateParsedTemplates(LPTMap);
+ }
+
+ clang::TypoCorrection
+ CorrectTypo(const clang::DeclarationNameInfo &Typo, int LookupKind,
+ clang::Scope *S, clang::CXXScopeSpec *SS,
+ clang::CorrectionCandidateCallback &CCC,
+ clang::DeclContext *MemberContext, bool EnteringContext,
+ const clang::ObjCObjectPointerType *OPT) override {
+ for (auto &Source : Sources) {
+ if (clang::TypoCorrection C =
+ Source->CorrectTypo(Typo, LookupKind, S, SS, CCC,
+ MemberContext, EnteringContext, OPT))
+ return C;
+ }
+ return clang::TypoCorrection();
+ }
+
+ bool MaybeDiagnoseMissingCompleteType(clang::SourceLocation Loc,
+ clang::QualType T) override {
+ for (auto &Source : Sources) {
+ if (Source->MaybeDiagnoseMissingCompleteType(Loc, T))
+ return true;
+ }
+ return false;
+ }
+};
+
+} // namespace lldb_private
+#endif // liblldb_ASTUtils_h_
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
index 38d088c458d..084c5b05907 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
@@ -6,6 +6,7 @@ add_lldb_library(lldbPluginExpressionParserClang PLUGIN
ASTDumper.cpp
ASTResultSynthesizer.cpp
ASTStructExtractor.cpp
+ ASTUtils.cpp
ClangASTSource.cpp
ClangExpressionDeclMap.cpp
ClangExpressionParser.cpp
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 6c9169852d4..95c70d247a1 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -36,6 +36,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/TargetSelect.h"
@@ -53,11 +54,17 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Signals.h"
+#include "ClangDiagnostic.h"
+#include "ClangExpressionParser.h"
+#include "ClangUserExpression.h"
+
+#include "ASTUtils.h"
#include "ClangASTSource.h"
#include "ClangDiagnostic.h"
#include "ClangExpressionDeclMap.h"
#include "ClangExpressionHelper.h"
#include "ClangExpressionParser.h"
+#include "ClangHost.h"
#include "ClangModulesDeclVendor.h"
#include "ClangPersistentVariables.h"
#include "IRForTarget.h"
@@ -210,15 +217,58 @@ private:
std::shared_ptr<clang::TextDiagnosticBuffer> m_passthrough;
};
+static void
+SetupModuleHeaderPaths(CompilerInstance *compiler,
+ std::vector<ConstString> include_directories,
+ lldb::TargetSP target_sp) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ HeaderSearchOptions &search_opts = compiler->getHeaderSearchOpts();
+
+ for (ConstString dir : include_directories) {
+ search_opts.AddPath(dir.AsCString(), frontend::System, false, true);
+ LLDB_LOG(log, "Added user include dir: {0}", dir);
+ }
+
+ llvm::SmallString<128> module_cache;
+ auto props = ModuleList::GetGlobalModuleListProperties();
+ props.GetClangModulesCachePath().GetPath(module_cache);
+ search_opts.ModuleCachePath = module_cache.str();
+ LLDB_LOG(log, "Using module cache path: {0}", module_cache.c_str());
+
+ FileSpec clang_resource_dir = GetClangResourceDir();
+ std::string resource_dir = clang_resource_dir.GetPath();
+ if (FileSystem::Instance().IsDirectory(resource_dir)) {
+ search_opts.ResourceDir = resource_dir;
+ std::string resource_include = resource_dir + "/include";
+ search_opts.AddPath(resource_include, frontend::System, false, true);
+
+ LLDB_LOG(log, "Added resource include dir: {0}", resource_include);
+ }
+
+ search_opts.ImplicitModuleMaps = true;
+
+ std::vector<std::string> system_include_directories =
+ target_sp->GetPlatform()->GetSystemIncludeDirectories(
+ lldb::eLanguageTypeC_plus_plus);
+
+ for (const std::string &include_dir : system_include_directories) {
+ search_opts.AddPath(include_dir, frontend::System, false, true);
+
+ LLDB_LOG(log, "Added system include dir: {0}", include_dir);
+ }
+}
+
//===----------------------------------------------------------------------===//
// Implementation of ClangExpressionParser
//===----------------------------------------------------------------------===//
-ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
- Expression &expr,
- bool generate_debug_info)
+ClangExpressionParser::ClangExpressionParser(
+ ExecutionContextScope *exe_scope, Expression &expr,
+ bool generate_debug_info, std::vector<ConstString> include_directories)
: ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(),
- m_pp_callbacks(nullptr) {
+ m_pp_callbacks(nullptr),
+ m_include_directories(std::move(include_directories)) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
// We can't compile expressions without a target. So if the exe_scope is
@@ -442,6 +492,31 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
// long time parsing and importing debug information.
lang_opts.SpellChecking = false;
+ auto &clang_expr = *static_cast<ClangUserExpression *>(&m_expr);
+ if (clang_expr.DidImportCxxModules()) {
+ LLDB_LOG(log, "Adding lang options for importing C++ modules");
+
+ lang_opts.Modules = true;
+ // We want to implicitly build modules.
+ lang_opts.ImplicitModules = true;
+ // To automatically import all submodules when we import 'std'.
+ lang_opts.ModulesLocalVisibility = false;
+
+ // We use the @import statements, so we need this:
+ // FIXME: We could use the modules-ts, but that currently doesn't work.
+ lang_opts.ObjC = true;
+
+ // Options we need to parse libc++ code successfully.
+ // FIXME: We should ask the driver for the appropriate default flags.
+ lang_opts.GNUMode = true;
+ lang_opts.GNUKeywords = true;
+ lang_opts.DoubleSquareBracketAttributes = true;
+ lang_opts.CPlusPlus11 = true;
+
+ SetupModuleHeaderPaths(m_compiler.get(), m_include_directories,
+ target_sp);
+ }
+
if (process_sp && lang_opts.ObjC) {
if (process_sp->GetObjCLanguageRuntime()) {
if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() ==
@@ -522,17 +597,6 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
m_compiler->createASTContext();
clang::ASTContext &ast_context = m_compiler->getASTContext();
- ClangExpressionHelper *type_system_helper =
- dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
- ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap();
-
- if (decl_map) {
- llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source(
- decl_map->CreateProxy());
- decl_map->InstallASTContext(ast_context, m_compiler->getFileManager());
- ast_context.setExternalSource(ast_source);
- }
-
m_ast_context.reset(
new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str()));
m_ast_context->setASTContext(&ast_context);
@@ -874,12 +938,6 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager,
ClangExpressionHelper *type_system_helper =
dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
- ASTConsumer *ast_transformer =
- type_system_helper->ASTTransformer(m_code_generator.get());
-
- if (ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap())
- decl_map->InstallCodeGenerator(m_code_generator.get());
-
// If we want to parse for code completion, we need to attach our code
// completion consumer to the Sema and specify a completion position.
// While parsing the Sema will call this consumer with the provided
@@ -894,17 +952,65 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager,
PP.SetCodeCompletionPoint(main_file, completion_line, completion_column);
}
+ ASTConsumer *ast_transformer =
+ type_system_helper->ASTTransformer(m_code_generator.get());
+
+ std::unique_ptr<clang::ASTConsumer> Consumer;
if (ast_transformer) {
- ast_transformer->Initialize(m_compiler->getASTContext());
- ParseAST(m_compiler->getPreprocessor(), ast_transformer,
- m_compiler->getASTContext(), false, TU_Complete,
- completion_consumer);
+ Consumer.reset(new ASTConsumerForwarder(ast_transformer));
+ } else if (m_code_generator) {
+ Consumer.reset(new ASTConsumerForwarder(m_code_generator.get()));
} else {
- m_code_generator->Initialize(m_compiler->getASTContext());
- ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(),
- m_compiler->getASTContext(), false, TU_Complete,
- completion_consumer);
+ Consumer.reset(new ASTConsumer());
+ }
+
+ clang::ASTContext &ast_context = m_compiler->getASTContext();
+
+ m_compiler->setSema(new Sema(m_compiler->getPreprocessor(), ast_context,
+ *Consumer, TU_Complete, completion_consumer));
+ m_compiler->setASTConsumer(std::move(Consumer));
+
+ if (ast_context.getLangOpts().Modules)
+ m_compiler->createModuleManager();
+
+ ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap();
+ if (decl_map) {
+ decl_map->InstallCodeGenerator(&m_compiler->getASTConsumer());
+
+ clang::ExternalASTSource *ast_source = decl_map->CreateProxy();
+
+ if (ast_context.getExternalSource()) {
+ auto module_wrapper =
+ new ExternalASTSourceWrapper(ast_context.getExternalSource());
+
+ auto ast_source_wrapper = new ExternalASTSourceWrapper(ast_source);
+
+ auto multiplexer =
+ new SemaSourceWithPriorities(*module_wrapper, *ast_source_wrapper);
+ IntrusiveRefCntPtr<ExternalASTSource> Source(multiplexer);
+ ast_context.setExternalSource(Source);
+ } else {
+ ast_context.setExternalSource(ast_source);
+ }
+ decl_map->InstallASTContext(ast_context, m_compiler->getFileManager());
+ }
+
+ // Check that the ASTReader is properly attached to ASTContext and Sema.
+ if (ast_context.getLangOpts().Modules) {
+ assert(m_compiler->getASTContext().getExternalSource() &&
+ "ASTContext doesn't know about the ASTReader?");
+ assert(m_compiler->getSema().getExternalSource() &&
+ "Sema doesn't know about the ASTReader?");
+ }
+
+ {
+ llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(
+ &m_compiler->getSema());
+ ParseAST(m_compiler->getSema(), false, false);
}
+ // Destroy the Sema. This is necessary because we want to emulate the
+ // original behavior of ParseAST (which also destroys the Sema after parsing).
+ m_compiler->setSema(nullptr);
diag_buf->EndSourceFile();
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
index 1183b169f6b..610008efdd4 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
@@ -52,9 +52,14 @@ public:
///
/// \param[in] expr
/// The expression to be parsed.
+ ///
+ /// @param[in] include_directories
+ /// List of include directories that should be used when parsing the
+ /// expression.
//------------------------------------------------------------------
ClangExpressionParser(ExecutionContextScope *exe_scope, Expression &expr,
- bool generate_debug_info);
+ bool generate_debug_info,
+ std::vector<ConstString> include_directories = {});
//------------------------------------------------------------------
/// Destructor
@@ -187,6 +192,8 @@ private:
LLDBPreprocessorCallbacks *m_pp_callbacks; ///< Called when the preprocessor
///encounters module imports
std::unique_ptr<ClangASTContext> m_ast_context;
+
+ std::vector<ConstString> m_include_directories;
};
}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
index 803ea1a4562..5be376ea3fa 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -178,8 +178,8 @@ static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp,
bool ClangExpressionSourceCode::GetText(std::string &text,
lldb::LanguageType wrapping_language,
bool static_method,
- ExecutionContext &exe_ctx,
- bool add_locals) const {
+ ExecutionContext &exe_ctx, bool add_locals,
+ llvm::ArrayRef<std::string> modules) const {
const char *target_specific_defines = "typedef signed char BOOL;\n";
std::string module_macros;
@@ -273,6 +273,15 @@ bool ClangExpressionSourceCode::GetText(std::string &text,
break;
}
+ // Generate a list of @import statements that will import the specified
+ // module into our expression.
+ std::string module_imports;
+ for (const std::string &module : modules) {
+ module_imports.append("@import ");
+ module_imports.append(module);
+ module_imports.append(";\n");
+ }
+
StreamString wrap_stream;
wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(),
@@ -298,28 +307,31 @@ bool ClangExpressionSourceCode::GetText(std::string &text,
default:
break;
case lldb::eLanguageTypeC:
- wrap_stream.Printf("void \n"
+ wrap_stream.Printf("%s"
+ "void \n"
"%s(void *$__lldb_arg) \n"
"{ \n"
" %s; \n"
"%s"
"} \n",
- m_name.c_str(), lldb_local_var_decls.GetData(),
- tagged_body.c_str());
+ module_imports.c_str(), m_name.c_str(),
+ lldb_local_var_decls.GetData(), tagged_body.c_str());
break;
case lldb::eLanguageTypeC_plus_plus:
- wrap_stream.Printf("void \n"
+ wrap_stream.Printf("%s"
+ "void \n"
"$__lldb_class::%s(void *$__lldb_arg) \n"
"{ \n"
" %s; \n"
"%s"
"} \n",
- m_name.c_str(), lldb_local_var_decls.GetData(),
- tagged_body.c_str());
+ module_imports.c_str(), m_name.c_str(),
+ lldb_local_var_decls.GetData(), tagged_body.c_str());
break;
case lldb::eLanguageTypeObjC:
if (static_method) {
wrap_stream.Printf(
+ "%s"
"@interface $__lldb_objc_class ($__lldb_category) \n"
"+(void)%s:(void *)$__lldb_arg; \n"
"@end \n"
@@ -329,9 +341,11 @@ bool ClangExpressionSourceCode::GetText(std::string &text,
"%s"
"} \n"
"@end \n",
- m_name.c_str(), m_name.c_str(), tagged_body.c_str());
+ module_imports.c_str(), m_name.c_str(), m_name.c_str(),
+ tagged_body.c_str());
} else {
wrap_stream.Printf(
+ "%s"
"@interface $__lldb_objc_class ($__lldb_category) \n"
"-(void)%s:(void *)$__lldb_arg; \n"
"@end \n"
@@ -341,7 +355,8 @@ bool ClangExpressionSourceCode::GetText(std::string &text,
"%s"
"} \n"
"@end \n",
- m_name.c_str(), m_name.c_str(), tagged_body.c_str());
+ module_imports.c_str(), m_name.c_str(), m_name.c_str(),
+ tagged_body.c_str());
}
break;
}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
index 28ec090c84d..3f20644d33c 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
@@ -32,10 +32,25 @@ public:
uint32_t GetNumBodyLines();
+ /// Generates the source code that will evaluate the expression.
+ ///
+ /// \param text output parameter containing the source code string.
+ /// \param wrapping_language If the expression is supossed to be wrapped,
+ /// then this is the language that should be used for that.
+ /// \param static_method True iff the expression is valuated inside a static
+ /// Objective-C method.
+ /// \param exe_ctx The execution context in which the expression will be
+ /// evaluated.
+ /// \param add_locals True iff local variables should be injected into the
+ /// expression source code.
+ /// \param modules A list of (C++) modules that the expression should import.
+ ///
+ /// \return true iff the source code was successfully generated.
bool GetText(std::string &text, lldb::LanguageType wrapping_language,
bool static_method,
ExecutionContext &exe_ctx,
- bool add_locals) const;
+ bool add_locals,
+ llvm::ArrayRef<std::string> modules) const;
// Given a string returned by GetText, find the beginning and end of the body
// passed to CreateWrapped. Return true if the bounds could be found. This
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index fc71c4a9337..465a65aed0b 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -37,6 +37,7 @@
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
@@ -397,7 +398,8 @@ static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) {
}
void ClangUserExpression::UpdateLanguageForExpr(
- DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
+ DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
+ std::vector<std::string> modules_to_import) {
m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown;
std::string prefix = m_expr_prefix;
@@ -417,8 +419,8 @@ void ClangUserExpression::UpdateLanguageForExpr(
m_expr_lang = lldb::eLanguageTypeC;
if (!source_code->GetText(m_transformed_text, m_expr_lang,
- m_in_static_method, exe_ctx,
- !m_ctx_obj)) {
+ m_in_static_method, exe_ctx, !m_ctx_obj,
+ modules_to_import)) {
diagnostic_manager.PutString(eDiagnosticSeverityError,
"couldn't construct expression body");
return;
@@ -436,8 +438,67 @@ void ClangUserExpression::UpdateLanguageForExpr(
}
}
+static bool SupportsCxxModuleImport(lldb::LanguageType language) {
+ switch (language) {
+ case lldb::eLanguageTypeC_plus_plus:
+ case lldb::eLanguageTypeC_plus_plus_03:
+ case lldb::eLanguageTypeC_plus_plus_11:
+ case lldb::eLanguageTypeC_plus_plus_14:
+ case lldb::eLanguageTypeObjC_plus_plus:
+ return true;
+ default:
+ return false;
+ }
+}
+
+std::vector<std::string>
+ClangUserExpression::GetModulesToImport(ExecutionContext &exe_ctx) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ if (!SupportsCxxModuleImport(Language()))
+ return {};
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (!target || !target->GetEnableImportStdModule())
+ return {};
+
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (!frame)
+ return {};
+
+ Block *block = frame->GetFrameBlock();
+ if (!block)
+ return {};
+
+ SymbolContext sc;
+ block->CalculateSymbolContext(&sc);
+ if (!sc.comp_unit)
+ return {};
+
+ if (log) {
+ for (const SourceModule &m : sc.comp_unit->GetImportedModules()) {
+ LLDB_LOG(log, "Found module in compile unit: {0:$[.]} - include dir: {1}",
+ llvm::make_range(m.path.begin(), m.path.end()), m.search_path);
+ }
+ }
+
+ for (const SourceModule &m : sc.comp_unit->GetImportedModules())
+ m_include_directories.push_back(m.search_path);
+
+ // Check if we imported 'std' or any of its submodules.
+ // We currently don't support importing any other modules in the expression
+ // parser.
+ for (const SourceModule &m : sc.comp_unit->GetImportedModules())
+ if (!m.path.empty() && m.path.front() == ConstString("std"))
+ return {"std"};
+
+ return {};
+}
+
bool ClangUserExpression::PrepareForParsing(
DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
InstallContext(exe_ctx);
if (!SetupPersistentState(diagnostic_manager, exe_ctx))
@@ -458,7 +519,13 @@ bool ClangUserExpression::PrepareForParsing(
SetupDeclVendor(exe_ctx, m_target);
- UpdateLanguageForExpr(diagnostic_manager, exe_ctx);
+ std::vector<std::string> used_modules = GetModulesToImport(exe_ctx);
+ m_imported_cpp_modules = !used_modules.empty();
+
+ LLDB_LOG(log, "List of imported modules in expression: {0}",
+ llvm::make_range(used_modules.begin(), used_modules.end()));
+
+ UpdateLanguageForExpr(diagnostic_manager, exe_ctx, used_modules);
return true;
}
@@ -517,7 +584,8 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
// succeeds or the rewrite parser we might make if it fails. But the
// parser_sp will never be empty.
- ClangExpressionParser parser(exe_scope, *this, generate_debug_info);
+ ClangExpressionParser parser(exe_scope, *this, generate_debug_info,
+ m_include_directories);
unsigned num_errors = parser.Parse(diagnostic_manager);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
index dd50b83b20c..54ad2d53420 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -167,6 +167,8 @@ public:
lldb::ExpressionVariableSP
GetResultAfterDematerialization(ExecutionContextScope *exe_scope) override;
+ bool DidImportCxxModules() const { return m_imported_cpp_modules; }
+
private:
//------------------------------------------------------------------
/// Populate m_in_cplusplus_method and m_in_objectivec_method based on the
@@ -180,8 +182,10 @@ private:
lldb::addr_t struct_address,
DiagnosticManager &diagnostic_manager) override;
+ std::vector<std::string> GetModulesToImport(ExecutionContext &exe_ctx);
void UpdateLanguageForExpr(DiagnosticManager &diagnostic_manager,
- ExecutionContext &exe_ctx);
+ ExecutionContext &exe_ctx,
+ std::vector<std::string> modules_to_import);
bool SetupPersistentState(DiagnosticManager &diagnostic_manager,
ExecutionContext &exe_ctx);
bool PrepareForParsing(DiagnosticManager &diagnostic_manager,
@@ -206,6 +210,8 @@ private:
/// The language type of the current expression.
lldb::LanguageType m_expr_lang = lldb::eLanguageTypeUnknown;
+ /// The include directories that should be used when parsing the expression.
+ std::vector<ConstString> m_include_directories;
/// The absolute character position in the transformed source code where the
/// user code (as typed by the user) starts. If the variable is empty, then we
@@ -216,6 +222,9 @@ private:
/// The object (if any) in which context the expression is evaluated.
/// See the comment to `UserExpression::Evaluate` for details.
ValueObject *m_ctx_obj;
+
+ /// True iff this expression explicitly imported C++ modules.
+ bool m_imported_cpp_modules = false;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
index 5100b174976..87a7e518173 100644
--- a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
+++ b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
@@ -263,6 +263,25 @@ bool PlatformLinux::CanDebugProcess() {
}
}
+std::vector<std::string>
+PlatformLinux::GetSystemIncludeDirectories(lldb::LanguageType lang) {
+ std::string sys_root = GetSDKRootDirectory().AsCString("");
+ switch (lang) {
+ case lldb::eLanguageTypeC:
+ case lldb::eLanguageTypeC89:
+ case lldb::eLanguageTypeC99:
+ case lldb::eLanguageTypeC11:
+ case lldb::eLanguageTypeC_plus_plus:
+ case lldb::eLanguageTypeC_plus_plus_03:
+ case lldb::eLanguageTypeC_plus_plus_11:
+ case lldb::eLanguageTypeC_plus_plus_14:
+ case lldb::eLanguageTypeObjC_plus_plus:
+ return {sys_root + "/usr/include/"};
+ default:
+ return {};
+ }
+}
+
// For local debugging, Linux will override the debug logic to use llgs-launch
// rather than lldb-launch, llgs-attach. This differs from current lldb-
// launch, debugserver-attach approach on MacOSX.
diff --git a/lldb/source/Plugins/Platform/Linux/PlatformLinux.h b/lldb/source/Plugins/Platform/Linux/PlatformLinux.h
index 2b05c2705fd..56c9ed3db31 100644
--- a/lldb/source/Plugins/Platform/Linux/PlatformLinux.h
+++ b/lldb/source/Plugins/Platform/Linux/PlatformLinux.h
@@ -52,6 +52,9 @@ public:
bool CanDebugProcess() override;
+ std::vector<std::string>
+ GetSystemIncludeDirectories(lldb::LanguageType lang) override;
+
lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info,
Debugger &debugger, Target *target,
Status &error) override;
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index ec08a2a24c4..a1bf4d9de01 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -3327,6 +3327,9 @@ static constexpr PropertyDefinition g_properties[] = {
{"auto-import-clang-modules", OptionValue::eTypeBoolean, false, true,
nullptr, {},
"Automatically load Clang modules referred to by the program."},
+ {"import-std-module", OptionValue::eTypeBoolean, false, false,
+ nullptr, {},
+ "Import the C++ std module to improve debugging STL containers."},
{"auto-apply-fixits", OptionValue::eTypeBoolean, false, true, nullptr,
{}, "Automatically apply fix-it hints to expressions."},
{"notify-about-fixits", OptionValue::eTypeBoolean, false, true, nullptr,
@@ -3465,6 +3468,7 @@ enum {
ePropertyDebugFileSearchPaths,
ePropertyClangModuleSearchPaths,
ePropertyAutoImportClangModules,
+ ePropertyImportStdModule,
ePropertyAutoApplyFixIts,
ePropertyNotifyAboutFixIts,
ePropertySaveObjects,
@@ -3887,6 +3891,12 @@ bool TargetProperties::GetEnableAutoImportClangModules() const {
nullptr, idx, g_properties[idx].default_uint_value != 0);
}
+bool TargetProperties::GetEnableImportStdModule() const {
+ const uint32_t idx = ePropertyImportStdModule;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_properties[idx].default_uint_value != 0);
+}
+
bool TargetProperties::GetEnableAutoApplyFixIts() const {
const uint32_t idx = ePropertyAutoApplyFixIts;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
OpenPOWER on IntegriCloud