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<PathElem, FoundName<'a>>,
17 short: PathElem,
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<PathElem, 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, _)] => {
74 Some(PathElem::Ident(ident.clone(), Disambiguator::ZERO))
75 }
76 [.., PathElem::Builtin(builtin, _)] if !builtin.is_tuple() && !builtin.is_str() => {
78 Some(PathElem::Builtin(*builtin, Disambiguator::ZERO))
79 }
80 [PathElem::Impl(ImplElem::Trait(impl_id))]
81 if let Some(trait_impl) = ctx.translated.trait_impls.get(*impl_id) =>
82 {
83 trait_impl_short_name(&ctx.translated.item_names, trait_impl)
84 .map(|short| PathElem::Ident(short, Disambiguator::ZERO))
85 }
86
87 _ => None,
88 };
89 if let Some(short) = candidate {
90 register_short_name_candidate(&mut short_names, short, name_slice, id);
91 }
92 }
93
94 for (short, found) in short_names {
95 if let FoundName::Unique { ids, .. } = found {
96 for id in ids {
97 let mut short_name = Name {
98 name: vec![short.clone()],
99 };
100 if let [.., mono @ PathElem::Instantiated(..)] =
101 ctx.translated.item_names[&id].name.as_slice()
102 {
103 short_name.name.push(mono.clone());
104 }
105 ctx.translated.short_names.insert(id, short_name);
106 }
107 }
108 }
109 }
110}
111
112fn trait_impl_short_name(
113 item_names: &SeqHashMap<ItemId, Name>,
114 trait_impl: &TraitImpl,
115) -> Option<String> {
116 fn args_to_idents(
117 item_names: &SeqHashMap<ItemId, Name>,
118 generics: &GenericArgs,
119 ) -> Vec<String> {
120 generics
121 .types
122 .iter()
123 .filter_map(|t| ty_to_idents(item_names, t))
124 .collect()
125 }
126
127 fn ty_to_idents(item_names: &SeqHashMap<ItemId, Name>, ty: &Ty) -> Option<String> {
128 Some(match ty.kind() {
129 TyKind::Scalar(scalar) => scalar.to_string(),
130 TyKind::Slice(..) => "slice".to_owned(),
131 TyKind::Array(..) => "array".to_owned(),
132 TyKind::Adt(tref) => item_to_ident(item_names, ItemId::Type(tref.id))?,
133 _ => return None,
134 })
135 }
136
137 fn item_to_ident(item_names: &SeqHashMap<ItemId, Name>, id: ItemId) -> Option<String> {
138 Some(item_names.get(&id)?.short_str()?.to_owned())
139 }
140
141 let trait_id = trait_impl.impl_trait.id;
142 let (self_ty, partial_trait_ref) = trait_impl.impl_trait.split_self();
143 let self_ty = self_ty.as_ref()?;
144
145 let mut candidate = vec!["impl".to_owned()];
146 candidate.push(item_to_ident(item_names, trait_id.into())?);
147 candidate.extend(args_to_idents(item_names, &partial_trait_ref.generics));
148 candidate.push("for".to_owned());
149 candidate.push(if let TyKind::TypeVar(_) = self_ty.kind() {
150 "T".to_string()
151 } else {
152 ty_to_idents(item_names, self_ty)?
153 });
154 if let TyKind::Adt(tref) = self_ty.kind() {
155 candidate.extend(args_to_idents(item_names, &tref.generics));
156 };
157 Some(candidate.join("_"))
158}