579 changes: 579 additions & 0 deletions lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_lldb_library(lldbPluginExpressionParserClang PLUGIN
ASTDumper.cpp
ASTResultSynthesizer.cpp
ASTStructExtractor.cpp
ASTUtils.cpp
ClangASTSource.cpp
ClangExpressionDeclMap.cpp
ClangExpressionParser.cpp
Expand Down
164 changes: 135 additions & 29 deletions lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -210,15 +217,58 @@ class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
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
Expand Down Expand Up @@ -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() ==
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,14 @@ class ClangExpressionParser : public ExpressionParser {
///
/// \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
Expand Down Expand Up @@ -187,6 +192,8 @@ class ClangExpressionParser : public ExpressionParser {
LLDBPreprocessorCallbacks *m_pp_callbacks; ///< Called when the preprocessor
///encounters module imports
std::unique_ptr<ClangASTContext> m_ast_context;

std::vector<ConstString> m_include_directories;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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(),
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,25 @@ class ClangExpressionSourceCode : public ExpressionSourceCode {

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
Expand Down
78 changes: 73 additions & 5 deletions lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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))
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);

Expand Down
11 changes: 10 additions & 1 deletion lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ class ClangUserExpression : public LLVMUserExpression {
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
Expand All @@ -180,8 +182,10 @@ class ClangUserExpression : public LLVMUserExpression {
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,
Expand All @@ -206,6 +210,8 @@ class ClangUserExpression : public LLVMUserExpression {

/// 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
Expand All @@ -216,6 +222,9 @@ class ClangUserExpression : public LLVMUserExpression {
/// 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
Expand Down
19 changes: 19 additions & 0 deletions lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Plugins/Platform/Linux/PlatformLinux.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ class PlatformLinux : public PlatformPOSIX {

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;
Expand Down
10 changes: 10 additions & 0 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -3465,6 +3468,7 @@ enum {
ePropertyDebugFileSearchPaths,
ePropertyClangModuleSearchPaths,
ePropertyAutoImportClangModules,
ePropertyImportStdModule,
ePropertyAutoApplyFixIts,
ePropertyNotifyAboutFixIts,
ePropertySaveObjects,
Expand Down Expand Up @@ -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(
Expand Down