charon_lib/transform/
compute_short_names.rs

1use std::collections::{HashMap, hash_map::Entry};
2
3use crate::ast::*;
4
5use super::{TransformCtx, ctx::TransformPass};
6
7enum FoundName<'a> {
8    Unique {
9        long: &'a [PathElem],
10        ids: Vec<AnyTransId>,
11    },
12    Multiple,
13}
14
15pub struct Transform;
16impl TransformPass for Transform {
17    fn transform_ctx(&self, ctx: &mut TransformCtx) {
18        let mut short_names: HashMap<&str, FoundName> = Default::default();
19        for (&id, name) in &ctx.translated.item_names {
20            let mut name_slice = name.name.as_slice();
21
22            // Trait impls are sufficiently unique information, so truncate starting from the
23            // rightmost impl.
24            if let Some((i, _)) = name_slice
25                .iter()
26                .enumerate()
27                .rfind(|(_, elem)| matches!(elem, PathElem::Impl(ImplElem::Trait(..), ..)))
28            {
29                name_slice = &name.name[i..];
30                let trunc_name = Name {
31                    name: name_slice.to_vec(),
32                };
33                ctx.translated.short_names.insert(id, trunc_name);
34            }
35
36            if let [prefix @ .., PathElem::Monomorphized(..)] = name_slice {
37                name_slice = prefix;
38            }
39            // Ignoring monomorphizations, if a name is the only one to end with a given suffix, we
40            // accumulate the ids of all the items with that name (there may be several thanks to
41            // monomorphizations).
42            match name_slice {
43                [.., PathElem::Ident(ident, _)] => match short_names.entry(ident) {
44                    Entry::Occupied(mut e) => match e.get_mut() {
45                        FoundName::Unique { long, ids } => {
46                            if *long == name_slice {
47                                ids.push(id)
48                            } else {
49                                e.insert(FoundName::Multiple);
50                            }
51                        }
52                        FoundName::Multiple => {}
53                    },
54                    Entry::Vacant(e) => {
55                        e.insert(FoundName::Unique {
56                            long: name_slice,
57                            ids: vec![id],
58                        });
59                    }
60                },
61                _ => {}
62            }
63        }
64
65        for (short, found) in short_names {
66            if let FoundName::Unique { ids, .. } = found {
67                for id in ids {
68                    let mut short_name = Name {
69                        name: vec![PathElem::Ident(short.to_owned(), Disambiguator::ZERO)],
70                    };
71                    if let [.., mono @ PathElem::Monomorphized(..)] =
72                        ctx.translated.item_names[&id].name.as_slice()
73                    {
74                        short_name.name.push(mono.clone());
75                    }
76                    ctx.translated.short_names.insert(id, short_name);
77                }
78            }
79        }
80    }
81}