Skip to content

Commit 57e65ac

Browse files
committed
[lldb][Format] Add new function basename highlight option to FormatEntity
1 parent 981cf4c commit 57e65ac

File tree

7 files changed

+193
-24
lines changed

7 files changed

+193
-24
lines changed

lldb/include/lldb/Core/FormatEntity.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,29 @@ struct Entry {
197197
return true;
198198
}
199199

200+
struct HighlightSettings {
201+
std::string prefix;
202+
std::string suffix;
203+
204+
enum class Kind : uint8_t {
205+
///< Don't highlight.
206+
None,
207+
208+
///< Highlight function basename
209+
///< (i.e., name without Scope and
210+
///< without template arguments).
211+
Basename,
212+
} kind = Kind::None;
213+
};
214+
200215
std::string string;
201216
std::string printf_format;
202217
std::vector<Entry> children;
203218
Type type;
204219
lldb::Format fmt = lldb::eFormatDefault;
205220
lldb::addr_t number = 0;
206221
bool deref = false;
222+
HighlightSettings highlight;
207223
};
208224

209225
bool Format(const Entry &entry, Stream &s, const SymbolContext *sc,

lldb/include/lldb/Target/Language.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,11 @@ class Language : public PluginInterface {
268268
// the reference has never been assigned
269269
virtual bool IsUninitializedReference(ValueObject &valobj);
270270

271-
virtual bool GetFunctionDisplayName(const SymbolContext *sc,
272-
const ExecutionContext *exe_ctx,
273-
FunctionNameRepresentation representation,
274-
Stream &s);
271+
virtual bool
272+
GetFunctionDisplayName(const SymbolContext *sc,
273+
const ExecutionContext *exe_ctx,
274+
FunctionNameRepresentation representation, Stream &s,
275+
const FormatEntity::Entry::HighlightSettings &);
275276

276277
virtual ConstString
277278
GetDemangledFunctionNameWithoutArguments(Mangled mangled) const {

lldb/source/Core/FormatEntity.cpp

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,7 +1654,8 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
16541654

16551655
if (language_plugin)
16561656
language_plugin_handled = language_plugin->GetFunctionDisplayName(
1657-
sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
1657+
sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss,
1658+
entry.highlight);
16581659

16591660
if (language_plugin_handled) {
16601661
s << ss.GetString();
@@ -1690,7 +1691,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
16901691
if (language_plugin)
16911692
language_plugin_handled = language_plugin->GetFunctionDisplayName(
16921693
sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
1693-
ss);
1694+
ss, entry.highlight);
16941695

16951696
if (language_plugin_handled) {
16961697
s << ss.GetString();
@@ -1724,7 +1725,8 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
17241725

17251726
if (language_plugin)
17261727
language_plugin_handled = language_plugin->GetFunctionDisplayName(
1727-
sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithArgs, ss);
1728+
sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithArgs, ss,
1729+
entry.highlight);
17281730

17291731
if (language_plugin_handled) {
17301732
s << ss.GetString();
@@ -2046,6 +2048,54 @@ static const Definition *FindEntry(const llvm::StringRef &format_str,
20462048
return parent;
20472049
}
20482050

2051+
static llvm::Expected<Entry::HighlightSettings>
2052+
ParseHighlightSettings(const Entry &entry) {
2053+
// FIXME: support other function.name-XXX types as well
2054+
if (entry.type != Entry::Type::FunctionNameWithArgs)
2055+
return llvm::createStringError(
2056+
"The 'highlight_basename' format can only be used on "
2057+
"${function.name-with-args}");
2058+
2059+
llvm::StringRef format = entry.printf_format;
2060+
if (!format.consume_front("highlight_"))
2061+
return llvm::createStringError(
2062+
"Expected 'highlight_' prefix not found in: %s.",
2063+
entry.printf_format.c_str());
2064+
2065+
Entry::HighlightSettings settings;
2066+
if (format.consume_front("basename")) {
2067+
settings.kind = Entry::HighlightSettings::Kind::Basename;
2068+
} else {
2069+
return llvm::createStringError(
2070+
"Unsupported highlight kind detected in: %s. "
2071+
"Currently supported: basename",
2072+
entry.printf_format.c_str());
2073+
}
2074+
2075+
llvm::SmallVector<llvm::StringRef, 1> matches;
2076+
// TODO: support ${ansi.XXX} syntax. ExtractVariableInfo needs
2077+
// to be adjusted to support nested '{}'.
2078+
llvm::Regex color_pattern{R"(^\(([a-z\.]+)\)$)"};
2079+
if (!color_pattern.match(format, &matches))
2080+
return llvm::createStringError("Couldn't find valid color variable in: %s. "
2081+
"Expected format: (ansi.some-color)",
2082+
entry.printf_format.c_str());
2083+
2084+
assert(matches.size() == 2);
2085+
2086+
std::string color_format = ("${" + matches[1] + "}").str();
2087+
std::string terminal_code = ansi::FormatAnsiTerminalCodes(color_format);
2088+
if (terminal_code.empty())
2089+
return llvm::createStringError("Invalid color variable '%s' found in: %s",
2090+
color_format.c_str(),
2091+
entry.printf_format.c_str());
2092+
2093+
settings.prefix = std::move(terminal_code);
2094+
settings.suffix = ansi::FormatAnsiTerminalCodes("${ansi.normal}");
2095+
2096+
return settings;
2097+
}
2098+
20492099
static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry,
20502100
uint32_t depth) {
20512101
Status error;
@@ -2201,6 +2251,7 @@ static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry,
22012251
if (error.Fail())
22022252
return error;
22032253
bool verify_is_thread_id = false;
2254+
bool parse_highlight_settings = false;
22042255
Entry entry;
22052256
if (!variable_format.empty()) {
22062257
entry.printf_format = variable_format.str();
@@ -2266,6 +2317,8 @@ static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry,
22662317
clear_printf = true;
22672318
} else if (entry.printf_format == "tid") {
22682319
verify_is_thread_id = true;
2320+
} else if (entry.printf_format.find("highlight_") == 0) {
2321+
parse_highlight_settings = true;
22692322
} else {
22702323
error = Status::FromErrorStringWithFormat(
22712324
"invalid format: '%s'", entry.printf_format.c_str());
@@ -2307,6 +2360,14 @@ static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry,
23072360
"the 'tid' format can only be used on "
23082361
"${thread.id} and ${thread.protocol_id}");
23092362
}
2363+
} else if (parse_highlight_settings) {
2364+
auto highlight_or_err = ParseHighlightSettings(entry);
2365+
if (highlight_or_err) {
2366+
entry.highlight = std::move(*highlight_or_err);
2367+
entry.printf_format.clear();
2368+
} else {
2369+
error = Status::FromError(highlight_or_err.takeError());
2370+
}
23102371
}
23112372

23122373
switch (entry.type) {

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/StringRef.h"
2020
#include "llvm/Demangle/ItaniumDemangle.h"
2121

22+
#include "lldb/Core/Demangle.h"
2223
#include "lldb/Core/Mangled.h"
2324
#include "lldb/Core/Module.h"
2425
#include "lldb/Core/PluginManager.h"
@@ -178,7 +179,7 @@ static bool IsTrivialBasename(const llvm::StringRef &basename) {
178179
/// but replaces each argument type with the variable name
179180
/// and the corresponding pretty-printed value
180181
static bool PrettyPrintFunctionNameWithArgs(Stream &out_stream,
181-
char const *full_name,
182+
llvm::StringRef full_name,
182183
ExecutionContextScope *exe_scope,
183184
VariableList const &args) {
184185
CPlusPlusLanguage::MethodName cpp_method{ConstString(full_name)};
@@ -208,6 +209,42 @@ static bool PrettyPrintFunctionNameWithArgs(Stream &out_stream,
208209
return true;
209210
}
210211

212+
static bool PrettyPrintFunctionNameWithArgs(
213+
Stream &out_stream, llvm::StringRef full_name,
214+
ExecutionContextScope *exe_scope, VariableList const &args,
215+
const std::optional<FunctionNameInfo> &demangled_info,
216+
const FormatEntity::Entry::HighlightSettings &settings) {
217+
if (settings.kind == FormatEntity::Entry::HighlightSettings::Kind::None ||
218+
!demangled_info || !demangled_info->hasBasename())
219+
return PrettyPrintFunctionNameWithArgs(out_stream, full_name, exe_scope,
220+
args);
221+
222+
auto [base_start, base_end] = demangled_info->BasenameLocs;
223+
224+
// Dump anything before the basename.
225+
out_stream.PutCString(full_name.substr(0, base_start));
226+
227+
// Highlight the basename.
228+
out_stream.PutCString(settings.prefix);
229+
out_stream.PutCString(full_name.substr(base_start, base_end - base_start));
230+
out_stream.PutCString(settings.suffix);
231+
232+
// Dump anything between the basename and the argument list.
233+
if (demangled_info->ArgumentLocs.first > base_end)
234+
out_stream.PutCString(full_name.substr(
235+
base_end, demangled_info->ArgumentLocs.first - base_end));
236+
237+
// Dump arguments.
238+
out_stream.PutChar('(');
239+
FormatEntity::PrettyPrintFunctionArguments(out_stream, args, exe_scope);
240+
out_stream.PutChar(')');
241+
242+
// Dump anything after the argument list.
243+
out_stream.PutCString(full_name.substr(demangled_info->ArgumentLocs.second));
244+
245+
return true;
246+
}
247+
211248
bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
212249
// This method tries to parse simple method definitions which are presumably
213250
// most comman in user programs. Definitions that can be parsed by this
@@ -1699,7 +1736,8 @@ bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
16991736

17001737
bool CPlusPlusLanguage::GetFunctionDisplayName(
17011738
const SymbolContext *sc, const ExecutionContext *exe_ctx,
1702-
FunctionNameRepresentation representation, Stream &s) {
1739+
FunctionNameRepresentation representation, Stream &s,
1740+
const FormatEntity::Entry::HighlightSettings &settings) {
17031741
switch (representation) {
17041742
case FunctionNameRepresentation::eNameWithArgs: {
17051743
// Print the function name with arguments in it
@@ -1737,13 +1775,10 @@ bool CPlusPlusLanguage::GetFunctionDisplayName(
17371775
if (variable_list_sp)
17381776
variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
17391777
args);
1740-
if (args.GetSize() > 0) {
1741-
if (!PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args))
1742-
return false;
1743-
} else {
1744-
s.PutCString(cstr);
1745-
}
1746-
return true;
1778+
1779+
return PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args,
1780+
sc->function->GetDemangledInfo(),
1781+
settings);
17471782
}
17481783
} else if (sc->symbol) {
17491784
const char *cstr = sc->symbol->GetName().AsCString(nullptr);

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "llvm/ADT/StringRef.h"
1616

1717
#include "Plugins/Language/ClangCommon/ClangHighlighter.h"
18+
#include "lldb/Core/FormatEntity.h"
1819
#include "lldb/Target/Language.h"
1920
#include "lldb/Utility/ConstString.h"
2021
#include "lldb/lldb-private.h"
@@ -138,10 +139,10 @@ class CPlusPlusLanguage : public Language {
138139
ConstString
139140
GetDemangledFunctionNameWithoutArguments(Mangled mangled) const override;
140141

141-
bool GetFunctionDisplayName(const SymbolContext *sc,
142-
const ExecutionContext *exe_ctx,
143-
FunctionNameRepresentation representation,
144-
Stream &s) override;
142+
bool GetFunctionDisplayName(
143+
const SymbolContext *sc, const ExecutionContext *exe_ctx,
144+
FunctionNameRepresentation representation, Stream &s,
145+
const FormatEntity::Entry::HighlightSettings &) override;
145146

146147
static bool IsCPPMangledName(llvm::StringRef name);
147148

lldb/source/Target/Language.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -510,10 +510,10 @@ bool Language::IsNilReference(ValueObject &valobj) { return false; }
510510

511511
bool Language::IsUninitializedReference(ValueObject &valobj) { return false; }
512512

513-
bool Language::GetFunctionDisplayName(const SymbolContext *sc,
514-
const ExecutionContext *exe_ctx,
515-
FunctionNameRepresentation representation,
516-
Stream &s) {
513+
bool Language::GetFunctionDisplayName(
514+
const SymbolContext *sc, const ExecutionContext *exe_ctx,
515+
FunctionNameRepresentation representation, Stream &s,
516+
const FormatEntity::Entry::HighlightSettings &) {
517517
return false;
518518
}
519519

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# UNSUPPORTED: system-windows
2+
# Test highlighting of function basenames.
3+
4+
# RUN: split-file %s %t
5+
# RUN: %build %t/main.cpp -o %t.out
6+
# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 | FileCheck %s --check-prefix=CHECK-COLOR
7+
8+
#--- main.cpp
9+
namespace ns {
10+
template<typename T>
11+
struct Bar {
12+
template<typename K>
13+
T bar(K k) const & { return 1.0f; }
14+
};
15+
16+
template<typename T>
17+
struct Foo {
18+
template<typename K>
19+
void foo() const volatile && {
20+
Bar<float> b;
21+
b.bar(b);
22+
}
23+
};
24+
25+
template<typename T>
26+
T func() {
27+
ns::Foo<int>{}.foo<int>();
28+
return T{};
29+
}
30+
} // namespace ns
31+
32+
int main() {
33+
ns::func<ns::Foo<int>>();
34+
return 0;
35+
}
36+
37+
#--- commands.input
38+
settings set use-color true
39+
settings set -f frame-format "frame ${function.name-with-args:%highlight_basename(ansi.fg.cyan)}\n"
40+
break set -n bar
41+
42+
run
43+
bt
44+
# CHECK-COLOR: frame float ns::Bar<float>::bar<ns::Bar<float>>(this={{.*}}, k=Bar<float> @ {{.*}}) const &
45+
# CHECK-COLOR: frame void ns::Foo<int>::foo<int>(this={{.*}}) const volatile &&
46+
# CHECK-COLOR: frame ns::Foo<int> ns::func<ns::Foo<int>>()
47+
# CHECK-COLOR: frame main
48+
49+
settings set -f frame-format "frame ${function.name-with-args:%highlight_basename(ansi.bg.green)}\n"
50+
bt
51+
52+
# CHECK-COLOR: frame float ns::Bar<float>::bar<ns::Bar<float>>(this={{.*}}, k=Bar<float> @ {{.*}}) const &
53+
# CHECK-COLOR: frame void ns::Foo<int>::foo<int>(this={{.*}}) const volatile &&
54+
# CHECK-COLOR: frame ns::Foo<int> ns::func<ns::Foo<int>>()
55+
# CHECK-COLOR: frame main

0 commit comments

Comments
 (0)