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