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:
Geoff Romer
2026-06-10 18:19:07 +00:00
committed by GitHub
parent 7871237c15
commit b04634a0cd
+49
View File
@@ -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"
)