-
Notifications
You must be signed in to change notification settings - Fork 341
[Syntax Highlighting] Add name and parameters syntax highlighting in Swift backtraces #10710
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: swift/release/6.2
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
source/Plugins/Language/CPlusPlus/LanguageCPlusPlusProperties.td | ||
source/Plugins/Language/Swift/LanguageSwiftProperties.td |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,6 +73,11 @@ struct DemangledNameInfo { | |
bool hasBasename() const { | ||
return BasenameRange.second > BasenameRange.first; | ||
} | ||
|
||
/// Returns \c true if this object holds a valid arguments range. | ||
bool hasArguments() const { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This diff should disappear once the following is merged: |
||
return ArgumentsRange.second > ArgumentsRange.first; | ||
} | ||
}; | ||
|
||
/// An OutputBuffer which keeps a record of where certain parts of a | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, it would be nice if this could live in Plugin/ (but maybe it's harder to pull off here?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These static methods are only called in |
||
llvm::StringRef setting_name); | ||
|
||
static bool CreateSettingForSwiftLanguagePlugin( | ||
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, | ||
llvm::StringRef description, bool is_global_property); | ||
}; | ||
|
||
} // namespace lldb_private | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
include "../../../../include/lldb/Core/PropertiesBase.td" | ||
Michael137 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
let Definition = "language_swift" in { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think should either be
It should use the same naming scheme. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're at the mercy of how settings for plugins are named. They all start with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's make sure to update the docs upstream though to mention that Swift also has this setting now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to add some context, the CPlusPlus plugin also uses an |
||
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.">; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,219 @@ SwiftLanguage::GetDemangledFunctionNameWithoutArguments(Mangled mangled) const { | |
return mangled_name; | ||
} | ||
|
||
static std::optional<llvm::StringRef> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. an optional StringRef is redundant unless there is a semantic difference between std::nullopt and an empty string. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would just return a StringRef here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW I did this in the upstream C++ plugin too. I did this because this way we can differentiate between "failed to extract this demangling info" versus "this part of the demangled string was not present, but nothing failed". In the failure case we return I guess instead of optional I should've probably used There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Opened a PR upstream to address this: |
||
GetDemangledBasename(const SymbolContext &sc) { | ||
Mangled mangled = sc.GetPossiblyInlinedFunctionName(); | ||
if (!mangled) | ||
return std::nullopt; | ||
|
||
auto demangled_name = mangled.GetDemangledName().GetStringRef(); | ||
if (demangled_name.empty()) | ||
return std::nullopt; | ||
|
||
const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo(); | ||
if (!info) | ||
return std::nullopt; | ||
|
||
// Function without a basename is nonsense. | ||
if (!info->hasBasename()) | ||
return std::nullopt; | ||
|
||
return demangled_name.slice(info->BasenameRange.first, | ||
info->BasenameRange.second); | ||
} | ||
|
||
static std::optional<llvm::StringRef> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will port the changes of the following PR once it's merged: |
||
GetDemangledFunctionPrefix(const SymbolContext &sc) { | ||
Mangled mangled = sc.GetPossiblyInlinedFunctionName(); | ||
if (!mangled) | ||
return std::nullopt; | ||
|
||
auto demangled_name = mangled.GetDemangledName().GetStringRef(); | ||
if (demangled_name.empty()) | ||
return std::nullopt; | ||
|
||
const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo(); | ||
if (!info) | ||
return std::nullopt; | ||
|
||
// Function without a basename is nonsense. | ||
if (!info->hasBasename()) | ||
return std::nullopt; | ||
|
||
return demangled_name.slice(info->PrefixRange.first, | ||
info->PrefixRange.second); | ||
} | ||
|
||
static std::optional<llvm::StringRef> | ||
GetDemangledFunctionSuffix(const SymbolContext &sc) { | ||
Mangled mangled = sc.GetPossiblyInlinedFunctionName(); | ||
if (!mangled) | ||
return std::nullopt; | ||
|
||
auto demangled_name = mangled.GetDemangledName().GetStringRef(); | ||
if (demangled_name.empty()) | ||
return std::nullopt; | ||
|
||
const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo(); | ||
if (!info) | ||
return std::nullopt; | ||
|
||
// Function without a basename is nonsense. | ||
if (!info->hasBasename()) | ||
return std::nullopt; | ||
|
||
return demangled_name.slice(info->SuffixRange.first, | ||
info->SuffixRange.second); | ||
} | ||
|
||
static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) { | ||
assert(sc.symbol); | ||
|
||
Mangled mangled = sc.GetPossiblyInlinedFunctionName(); | ||
if (!mangled) | ||
return false; | ||
|
||
auto demangled_name = mangled.GetDemangledName().GetStringRef(); | ||
if (demangled_name.empty()) | ||
return false; | ||
|
||
const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo(); | ||
if (!info) | ||
return false; | ||
|
||
// Function without a basename is nonsense. | ||
if (!info->hasBasename()) | ||
return false; | ||
|
||
if (info->ArgumentsRange.second < info->ArgumentsRange.first) | ||
return false; | ||
|
||
s << demangled_name.slice(info->ArgumentsRange.first, | ||
info->ArgumentsRange.second); | ||
|
||
return true; | ||
} | ||
|
||
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<llvm::StringRef> 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<llvm::StringRef> prefix = GetDemangledFunctionPrefix(sc); | ||
if (!prefix) | ||
return false; | ||
|
||
s << *prefix; | ||
|
||
return true; | ||
} | ||
case FormatEntity::Entry::Type::FunctionSuffix: { | ||
std::optional<llvm::StringRef> 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<OptionValueProperties>(GetSettingName()); | ||
m_collection_sp->Initialize(g_language_swift_properties); | ||
} | ||
|
||
FormatEntity::Entry GetFunctionNameFormat() const { | ||
return GetPropertyAtIndexAs<const FormatEntity::Entry>( | ||
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 { | ||
|
Uh oh!
There was an error while loading. Please reload this page.