charon_lib/transform/add_missing_info/
compute_short_names.rs1use std::collections::{HashMap, hash_map::Entry};
2
3use crate::ast::*;
4
5use crate::transform::{TransformCtx, ctx::TransformPass};
6
7enum FoundName<'a> {
8 Unique {
9 long: &'a [PathElem],
10 ids: Vec<ItemId>,
11 },
12 Multiple,
13}
14
15fn register_short_name_candidate<'a>(
16 short_names: &mut HashMap<String, FoundName<'a>>,
17 short: String,
18 long: &'a [PathElem],
19 id: ItemId,
20) {
21 match short_names.entry(short) {
22 Entry::Occupied(mut e) => match e.get_mut() {
23 FoundName::Unique {
24 long: found_long,
25 ids,
26 } => {
27 if *found_long == long {
28 ids.push(id)
29 } else {
30 e.insert(FoundName::Multiple);
31 }
32 }
33 FoundName::Multiple => {}
34 },
35 Entry::Vacant(e) => {
36 e.insert(FoundName::Unique {
37 long,
38 ids: vec![id],
39 });
40 }
41 }
42}
43
44pub struct Transform;
45impl TransformPass for Transform {
46 fn transform_ctx(&self, ctx: &mut TransformCtx) {
47 ctx.translated.short_names.clear();
48 let mut short_names: HashMap<String, FoundName> = Default::default();
49 for (&id, name) in &ctx.translated.item_names {
50 let mut name_slice = name.name.as_slice();
51
52 if let Some((i, _)) = name_slice
55 .iter()
56 .enumerate()
57 .rfind(|(_, elem)| matches!(elem, PathElem::Impl(ImplElem::Trait(..), ..)))
58 {
59 name_slice = &name.name[i..];
60 let trunc_name = Name {
61 name: name_slice.to_vec(),
62 };
63 ctx.translated.short_names.insert(id, trunc_name);
64 }
65
66 if let [prefix @ .., PathElem::Instantiated(..)] = name_slice {
67 name_slice = prefix;
68 }
69 let candidate = match name_slice {
73 [.., PathElem::Ident(ident, _)] => Some(ident.clone()),
74 [PathElem::Impl(ImplElem::Trait(impl_id))]
75 if let Some(trait_impl) = ctx.translated.trait_impls.get(*impl_id) =>
76 {
77 trait_impl_short_name(&ctx.translated.item_names, trait_impl)
78 }
79
80 _ => None,
81 };
82 if let Some(short) = candidate {
83 register_short_name_candidate(&mut short_names, short, name_slice, id);
84 }
85 }
86
87 for (short, found) in short_names {
88 if let FoundName::Unique { ids, .. } = found {
89 for id in ids {
90 let mut short_name = Name {
91 name: vec![PathElem::Ident(short.clone(), Disambiguator::ZERO)],
92 };
93 if let [.., mono @ PathElem::Instantiated(..)] =
94 ctx.translated.item_names[&id].name.as_slice()
95 {
96 short_name.name.push(mono.clone());
97 }
98 ctx.translated.short_names.insert(id, short_name);
99 }
100 }
101 }
102 }
103}
104
105fn trait_impl_short_name(
106 item_names: &SeqHashMap<ItemId, Name>,
107 trait_impl: &TraitImpl,
108) -> Option<String> {
109 fn args_to_idents(
110 item_names: &SeqHashMap<ItemId, Name>,
111 generics: &GenericArgs,
112 ) -> Vec<String> {
113 generics
114 .types
115 .iter()
116 .filter_map(|t| ty_to_idents(item_names, t))
117 .collect()
118 }
119
120 fn ty_to_idents(item_names: &SeqHashMap<ItemId, Name>, ty: &Ty) -> Option<String> {
121 Some(match ty.kind() {
122 TyKind::Literal(literal) => literal.to_string(),
123 TyKind::Slice(..) => "slice".to_owned(),
124 TyKind::Array(..) => "array".to_owned(),
125 TyKind::Adt(tref) => match tref.id {
126 TypeId::Adt(id) => item_to_ident(item_names, ItemId::Type(id))?,
127 TypeId::Builtin(builtin) => builtin.get_name().short_str()?.to_owned(),
128 TypeId::Tuple if tref.generics.types.is_empty() => "unit".to_owned(),
129 TypeId::Tuple => "tuple".to_owned(),
130 },
131 _ => return None,
132 })
133 }
134
135 fn item_to_ident(item_names: &SeqHashMap<ItemId, Name>, id: ItemId) -> Option<String> {
136 Some(item_names.get(&id)?.short_str()?.to_owned())
137 }
138
139 let trait_id = trait_impl.impl_trait.id;
140 let (self_ty, partial_trait_ref) = trait_impl.impl_trait.split_self();
141 let self_ty = self_ty.as_ref()?;
142
143 let mut candidate = vec!["impl".to_owned()];
144 candidate.push(item_to_ident(item_names, trait_id.into())?);
145 candidate.extend(args_to_idents(item_names, &partial_trait_ref.generics));
146 candidate.push("for".to_owned());
147 candidate.push(if let TyKind::TypeVar(_) = self_ty.kind() {
148 "T".to_string()
149 } else {
150 ty_to_idents(item_names, self_ty)?
151 });
152 if let TyKind::Adt(tref) = self_ty.kind() {
153 candidate.extend(args_to_idents(item_names, &tref.generics));
154 };
155 Some(candidate.join("_"))
156}