mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:00:11 +01:00
Implement a custom LLDB formatter for Carbon IDs (#7333)
This removes the inheritance noise, and adds label prefixes for
consistency with the raw textual format.
Before:
```
> p function_info.first_owning_decl_id
(Carbon::SemIR::InstId) {
Carbon::IdBase<Carbon::SemIR::InstId> = {
Carbon::AnyIdBase = (index = 0x50000023)
}
}
> p function_info.call_param_ranges.implicit_end_
(Carbon::SemIR::CallParamIndex) {
Carbon::IndexBase<Carbon::SemIR::CallParamIndex> = {
Carbon::IdBase<Carbon::SemIR::CallParamIndex> = {
Carbon::AnyIdBase = (index = 0x00000001)
}
}
}
```
After:
```
> p function_info.first_owning_decl_id
(Carbon::SemIR::InstId) inst50000023
> p function_info.call_param_ranges.implicit_end_
(Carbon::SemIR::CallParamIndex) call_param1
```
The benefit compounds when printing aggregates (which often lack `Dump`
support or omit information from it). For example, this change reduces
`p function_info` from 129 lines to just 31 (including reducing the
`call_param_ranges` field from 32 lines to just 1):
```
> p function_info
(Carbon::SemIR::Function) {
Carbon::SemIR::EntityWithParamsBase = {
name_id = name1
parent_scope_id = name_scope50000002
generic_id = generic<none>
first_param_node_id = nodeB
last_param_node_id = node12
pattern_block_id = inst_block5000000E
implicit_param_patterns_id = inst_block5000000A
param_patterns_id = inst_block0
is_extern = false
extern_library_id = library_name<none>
non_owning_decl_id = inst<none>
first_owning_decl_id = inst50000023
definition_id = inst<none>
}
Carbon::SemIR::FunctionFields = {
call_param_patterns_id = inst_block5000000C
call_params_id = inst_block5000000D
call_param_ranges = (implicit_end_ = call_param1, explicit_end_ = call_param1, return_end_ = call_param1)
return_type_inst_id = inst<none>
return_form_inst_id = inst<none>
return_pattern_id = inst<none>
special_function_kind = None
virtual_modifier = None
virtual_index = 0xffffffff
evaluation_mode = None
self_param_id = inst50000020
special_function_kind_data = any_raw<none>
body_block_ids = size=0 {}
}
}
```
This commit is contained in:
@@ -149,5 +149,54 @@ Example usage:
|
||||
print_dump(context, expr)
|
||||
|
||||
|
||||
# Returns true if sbtype is a Carbon ID type (i.e. is derived from
|
||||
# `Carbon::AnyIdBase`).
|
||||
def is_carbon_id(sbtype: lldb.SBType, internal_dict: Any) -> bool:
|
||||
for base in sbtype.get_bases_array():
|
||||
if "Carbon::AnyIdBase" in base.GetName():
|
||||
return True
|
||||
if is_carbon_id(base.type, internal_dict):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# Formats a Carbon ID value to roughly match its format in raw SemIR, without
|
||||
# calling any user code.
|
||||
def format_carbon_id(
|
||||
valobj: lldb.SBValue, internal_dict: Any, options: Any
|
||||
) -> str:
|
||||
# TODO: It would be safer and more efficient to get these by traversing the
|
||||
# member graph using the Python API, rather than by evaluating C++
|
||||
# expressions. However, that doesn't seem to work in this case
|
||||
# (`SBTypeStaticField.GetConstantValue` seems to be broken), and even if it
|
||||
# did, it would be fairly verbose and probably more brittle.
|
||||
label = valobj.EvaluateExpression("Label.Data")
|
||||
label_size = valobj.EvaluateExpression("Label.Length")
|
||||
if label and label_size:
|
||||
# Clamp the read size, to limit the impact of memory corruption.
|
||||
# 40 chars should be enough for any legitimate ID label.
|
||||
read_size = min(label_size.GetValueAsUnsigned(), 40)
|
||||
label_data = valobj.process.ReadMemory(
|
||||
label.GetValueAsAddress(), read_size, lldb.SBError()
|
||||
)
|
||||
label_str = label_data.decode("utf-8")
|
||||
else:
|
||||
label_str = "<unknown id>"
|
||||
|
||||
index_int = valobj.GetChildMemberWithName("index").GetValueAsUnsigned()
|
||||
if index_int == 0xFFFFFFFF:
|
||||
# We can't handle all the special cases that ID printing does, but we
|
||||
# can at least handle the most common one.
|
||||
index_str = "<none>"
|
||||
else:
|
||||
index_str = f"{index_int:X}"
|
||||
|
||||
return f"{label_str}{index_str}"
|
||||
|
||||
|
||||
def __lldb_init_module(debugger: Any, internal_dict: Any) -> None:
|
||||
RunCommand("command script add -f lldbinit.cmd_dump dump")
|
||||
RunCommand(
|
||||
"type summary add --python-function lldbinit.format_carbon_id"
|
||||
+ " --recognizer-function lldbinit.is_carbon_id"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user