From 6909a5f4de2e10678c2047c18b0e2d69038fdeb0 Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Tue, 17 Jun 2025 12:58:27 +0100 Subject: [PATCH] [lldb] add syntax highlighting infrastructure to Swift plugin --- lldb/.clang-format-ignore | 2 + lldb/include/lldb/Core/PluginManager.h | 8 + lldb/source/Core/PluginManager.cpp | 15 ++ .../Plugins/Language/Swift/CMakeLists.txt | 12 ++ .../Language/Swift/LanguageSwiftProperties.td | 8 + .../Plugins/Language/Swift/SwiftLanguage.cpp | 140 +++++++++++++++++- .../Plugins/Language/Swift/SwiftLanguage.h | 10 ++ 7 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 lldb/.clang-format-ignore create mode 100644 lldb/source/Plugins/Language/Swift/LanguageSwiftProperties.td diff --git a/lldb/.clang-format-ignore b/lldb/.clang-format-ignore new file mode 100644 index 0000000000000..7d01f936e3bb8 --- /dev/null +++ b/lldb/.clang-format-ignore @@ -0,0 +1,2 @@ +source/Plugins/Language/CPlusPlus/LanguageCPlusPlusProperties.td +source/Plugins/Language/Swift/LanguageSwiftProperties.td \ No newline at end of file diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h index c0213e3f8d3f6..0c988e5969538 100644 --- a/lldb/include/lldb/Core/PluginManager.h +++ b/lldb/include/lldb/Core/PluginManager.h @@ -610,6 +610,14 @@ class PluginManager { static bool CreateSettingForCPlusPlusLanguagePlugin( Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, llvm::StringRef description, bool is_global_property); + + static lldb::OptionValuePropertiesSP + GetSettingForSwiftLanguagePlugin(Debugger &debugger, + llvm::StringRef setting_name); + + static bool CreateSettingForSwiftLanguagePlugin( + Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, + llvm::StringRef description, bool is_global_property); }; } // namespace lldb_private diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp index c7ef83d82d6c7..8a19684d63f28 100644 --- a/lldb/source/Core/PluginManager.cpp +++ b/lldb/source/Core/PluginManager.cpp @@ -1766,6 +1766,7 @@ static constexpr llvm::StringLiteral kJITLoaderPluginName("jit-loader"); static constexpr llvm::StringLiteral kStructuredDataPluginName("structured-data"); static constexpr llvm::StringLiteral kCPlusPlusLanguagePlugin("cplusplus"); +static constexpr llvm::StringLiteral kSwiftLanguagePlugin("swift"); lldb::OptionValuePropertiesSP PluginManager::GetSettingForDynamicLoaderPlugin(Debugger &debugger, @@ -1937,3 +1938,17 @@ bool PluginManager::CreateSettingForCPlusPlusLanguagePlugin( "Settings for CPlusPlus language plug-ins", properties_sp, description, is_global_property); } + +lldb::OptionValuePropertiesSP +PluginManager::GetSettingForSwiftLanguagePlugin(Debugger &debugger, + llvm::StringRef setting_name) { + return GetSettingForPlugin(debugger, setting_name, kSwiftLanguagePlugin); +} + +bool PluginManager::CreateSettingForSwiftLanguagePlugin( + Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, + llvm::StringRef description, bool is_global_property) { + return CreateSettingForPlugin(debugger, kSwiftLanguagePlugin, + "Settings for Swift language plug-ins", + properties_sp, description, is_global_property); +} \ No newline at end of file diff --git a/lldb/source/Plugins/Language/Swift/CMakeLists.txt b/lldb/source/Plugins/Language/Swift/CMakeLists.txt index 78cc8db0e8811..bffce5b5ca49c 100644 --- a/lldb/source/Plugins/Language/Swift/CMakeLists.txt +++ b/lldb/source/Plugins/Language/Swift/CMakeLists.txt @@ -1,3 +1,11 @@ +lldb_tablegen(LanguageSwiftProperties.inc -gen-lldb-property-defs + SOURCE LanguageSwiftProperties.td + TARGET LLDBPluginLanguageSwiftPropertiesGen) + +lldb_tablegen(LanguageSwiftPropertiesEnum.inc -gen-lldb-property-enum-defs + SOURCE LanguageSwiftProperties.td + TARGET LLDBPluginLanguageSwiftPropertiesEnumGen) + set(LLVM_NO_RTTI 1) add_lldb_library(lldbPluginSwiftLanguage PLUGIN @@ -36,3 +44,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT SWIFT_COMPILER_MSVC_LIKE) target_compile_options(lldbPluginSwiftLanguage PRIVATE -Wno-dollar-in-identifier-extension) endif() + +add_dependencies(lldbPluginSwiftLanguage + LLDBPluginLanguageSwiftPropertiesGen + LLDBPluginLanguageSwiftPropertiesEnumGen) diff --git a/lldb/source/Plugins/Language/Swift/LanguageSwiftProperties.td b/lldb/source/Plugins/Language/Swift/LanguageSwiftProperties.td new file mode 100644 index 0000000000000..b863e32b52d89 --- /dev/null +++ b/lldb/source/Plugins/Language/Swift/LanguageSwiftProperties.td @@ -0,0 +1,8 @@ +include "../../../../include/lldb/Core/PropertiesBase.td" + +let Definition = "language_swift" in { + def FunctionNameFormat: Property<"function-name-format", "FormatEntity">, + Global, + DefaultStringValue<"${function.prefix}${ansi.fg.yellow}${function.basename}${ansi.normal}${function.formatted-arguments}${function.suffix}">, + Desc<"Swift specific frame format string to use when displaying stack frame information for threads.">; +} \ No newline at end of file diff --git a/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp b/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp index daec35f32f3f4..f2bbf2c7dcb2b 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp @@ -68,7 +68,7 @@ void SwiftLanguage::Initialize() { static ConstString g_SwiftStringStorageClass("_TtCs15__StringStorage"); static ConstString g_NSArrayClass1("_TtCs22__SwiftDeferredNSArray"); PluginManager::RegisterPlugin(GetPluginNameStatic(), "Swift Language", - CreateInstance); + CreateInstance, &DebuggerInitialize); lldb_private::formatters::NSString_Additionals::GetAdditionalSummaries() .emplace( @@ -1894,6 +1894,144 @@ SwiftLanguage::GetDemangledFunctionNameWithoutArguments(Mangled mangled) const { return mangled_name; } +static std::optional +GetDemangledBasename(const SymbolContext &sc) { + return std::nullopt; +} + +static std::optional +GetDemangledFunctionPrefix(const SymbolContext &sc) { + return std::nullopt; +} + +static std::optional +GetDemangledFunctionSuffix(const SymbolContext &sc) { + return std::nullopt; +} + +static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) { + return false; +} + +static VariableListSP GetFunctionVariableList(const SymbolContext &sc) { + assert(sc.function); + + if (sc.block) + if (Block *inline_block = sc.block->GetContainingInlinedBlock()) + return inline_block->GetBlockVariableList(true); + + return sc.function->GetBlock(true).GetBlockVariableList(true); +} + +bool SwiftLanguage::HandleFrameFormatVariable(const SymbolContext &sc, + const ExecutionContext *exe_ctx, + FormatEntity::Entry::Type type, + Stream &s) { + switch (type) { + case FormatEntity::Entry::Type::FunctionBasename: { + std::optional name = GetDemangledBasename(sc); + if (!name) + return false; + + s << *name; + + return true; + } + case FormatEntity::Entry::Type::FunctionFormattedArguments: { + // This ensures we print the arguments even when no debug-info is available. + // + // FIXME: we should have a Entry::Type::FunctionArguments and + // use it in the plugin.cplusplus.display.function-name-format + // once we have a "fallback operator" in the frame-format language. + if (!sc.function && sc.symbol) + return PrintDemangledArgumentList(s, sc); + std::string display_name = SwiftLanguageRuntime::DemangleSymbolAsString( + sc.function->GetMangled().GetMangledName().GetStringRef(), + SwiftLanguageRuntime::eSimplified, &sc, exe_ctx); + if (display_name.empty()) + return false; + + VariableList args; + if (auto variable_list_sp = GetFunctionVariableList(sc)) + variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument, + args); + + s << GetFunctionDisplayArgs(sc, args, exe_ctx); + return true; + } + case FormatEntity::Entry::Type::FunctionPrefix: { + std::optional prefix = GetDemangledFunctionPrefix(sc); + if (!prefix) + return false; + + s << *prefix; + + return true; + } + case FormatEntity::Entry::Type::FunctionSuffix: { + std::optional suffix = GetDemangledFunctionSuffix(sc); + if (!suffix) + return false; + + s << *suffix; + + return true; + } + + case FormatEntity::Entry::Type::FunctionScope: + case FormatEntity::Entry::Type::FunctionTemplateArguments: + case FormatEntity::Entry::Type::FunctionReturnRight: + case FormatEntity::Entry::Type::FunctionReturnLeft: + case FormatEntity::Entry::Type::FunctionQualifiers: + default: + return true; + } +} + +#define LLDB_PROPERTIES_language_swift +#include "LanguageSwiftProperties.inc" + +enum { +#define LLDB_PROPERTIES_language_swift +#include "LanguageSwiftPropertiesEnum.inc" +}; + +namespace { +class PluginProperties : public Properties { +public: + static llvm::StringRef GetSettingName() { return "display"; } + + PluginProperties() { + m_collection_sp = std::make_shared(GetSettingName()); + m_collection_sp->Initialize(g_language_swift_properties); + } + + FormatEntity::Entry GetFunctionNameFormat() const { + return GetPropertyAtIndexAs( + ePropertyFunctionNameFormat, {}); + } +}; +} // namespace + +static PluginProperties &GetGlobalPluginProperties() { + static PluginProperties g_settings; + return g_settings; +} + +FormatEntity::Entry SwiftLanguage::GetFunctionNameFormat() const { + return GetGlobalPluginProperties().GetFunctionNameFormat(); +} + +void SwiftLanguage::DebuggerInitialize(Debugger &debugger) { + if (!PluginManager::GetSettingForSwiftLanguagePlugin( + debugger, PluginProperties::GetSettingName())) { + PluginManager::CreateSettingForSwiftLanguagePlugin( + debugger, GetGlobalPluginProperties().GetValueProperties(), + "Properties for the Swift language plug-in.", + /*is_global_property=*/true); + } +} + namespace { using namespace swift::Demangle; struct AsyncInfo { diff --git a/lldb/source/Plugins/Language/Swift/SwiftLanguage.h b/lldb/source/Plugins/Language/Swift/SwiftLanguage.h index 9d51c2a3a012b..9a78a3dd85fc0 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftLanguage.h +++ b/lldb/source/Plugins/Language/Swift/SwiftLanguage.h @@ -130,6 +130,13 @@ class SwiftLanguage : public Language { llvm::StringRef GetInstanceVariableName() override { return "self"; } + bool HandleFrameFormatVariable(const SymbolContext &sc, + const ExecutionContext *exe_ctx, + FormatEntity::Entry::Type type, + Stream &s) override; + + FormatEntity::Entry GetFunctionNameFormat() const override; + /// Override that skips breakpoints inside await resume ("Q") async funclets. void FilterForLineBreakpoints( llvm::SmallVectorImpl &) const override; @@ -138,6 +145,9 @@ class SwiftLanguage : public Language { // PluginInterface protocol //------------------------------------------------------------------ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + +private: + static void DebuggerInitialize(Debugger &); }; } // namespace lldb_private