use rustc_hir::{
def::Res,
def_id::{CrateNum, DefId},
HirId,
};
use rustc_middle::{
metadata::ModChild,
ty::{AssocKind, GenericParamDef, GenericParamDefKind},
};
use rustc_span::symbol::Symbol;
use std::collections::{BTreeSet, HashMap, HashSet, VecDeque};
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct InherentEntry {
pub parent_def_id: DefId,
pub kind: AssocKind,
pub name: Symbol,
}
fn assert_impl_eq<T: Eq>() {}
#[allow(dead_code)]
fn assert_inherent_entry_members_impl_eq() {
assert_impl_eq::<DefId>();
assert_impl_eq::<AssocKind>();
assert_impl_eq::<Symbol>();
}
pub type InherentImplSet = BTreeSet<(DefId, DefId)>;
#[allow(clippy::module_name_repetitions)]
pub struct IdMapping {
old_crate: CrateNum,
new_crate: CrateNum,
toplevel_mapping: HashMap<DefId, (Res, Res)>,
non_mapped_items: HashSet<DefId>,
trait_item_mapping: HashMap<DefId, (Res, Res, DefId)>,
private_traits: HashSet<DefId>,
internal_mapping: HashMap<DefId, DefId>,
child_mapping: HashMap<DefId, BTreeSet<DefId>>,
reverse_mapping: HashMap<DefId, DefId>,
type_params: HashMap<DefId, GenericParamDef>,
inherent_items: HashMap<InherentEntry, InherentImplSet>,
}
impl IdMapping {
pub fn new(old_crate: CrateNum, new_crate: CrateNum) -> Self {
Self {
old_crate,
new_crate,
toplevel_mapping: HashMap::new(),
non_mapped_items: HashSet::new(),
trait_item_mapping: HashMap::new(),
private_traits: HashSet::new(),
internal_mapping: HashMap::new(),
child_mapping: HashMap::new(),
reverse_mapping: HashMap::new(),
type_params: HashMap::new(),
inherent_items: HashMap::new(),
}
}
pub fn add_export(&mut self, old: Res, new: Res) -> bool {
let (old_def_id, new_def_id) =
if let (Some(old_def_id), Some(new_def_id)) = (old.opt_def_id(), new.opt_def_id()) {
(old_def_id, new_def_id)
} else {
return false;
};
if !self.in_old_crate(old_def_id) || self.toplevel_mapping.contains_key(&old_def_id) {
return false;
}
self.toplevel_mapping.insert(old_def_id, (old, new));
self.reverse_mapping.insert(new_def_id, old_def_id);
true
}
pub fn add_non_mapped(&mut self, def_id: DefId) {
self.non_mapped_items.insert(def_id);
}
pub fn add_trait_item(&mut self, old: Res, new: Res, old_trait: DefId) {
let old_def_id = old.def_id();
assert!(self.in_old_crate(old_def_id));
self.trait_item_mapping
.insert(old_def_id, (old, new, old_trait));
self.reverse_mapping.insert(new.def_id(), old_def_id);
}
pub fn add_private_trait(&mut self, trait_def_id: DefId) {
self.private_traits.insert(trait_def_id);
}
pub fn add_internal_item(&mut self, old: DefId, new: DefId) {
assert!(
!self.internal_mapping.contains_key(&old),
"bug: overwriting {:?} => {:?} with {:?}!",
old,
self.internal_mapping[&old],
new
);
assert!(self.in_old_crate(old));
assert!(self.in_new_crate(new));
self.internal_mapping.insert(old, new);
self.reverse_mapping.insert(new, old);
}
pub fn add_subitem(&mut self, old_parent: DefId, old: DefId, new: DefId) {
self.add_internal_item(old, new);
self.child_mapping
.entry(old_parent)
.or_insert_with(Default::default)
.insert(old);
}
pub fn add_type_param(&mut self, param: &GenericParamDef) {
match param.kind {
GenericParamDefKind::Lifetime => unreachable!(),
GenericParamDefKind::Type { .. } => (),
GenericParamDefKind::Const { .. } => unreachable!(),
};
self.type_params.insert(param.def_id, param.clone());
}
pub fn get_type_param(&self, did: &DefId) -> &GenericParamDef {
&self.type_params[did]
}
pub fn is_non_mapped_defaulted_type_param(&self, def_id: DefId) -> bool {
self.non_mapped_items.contains(&def_id)
&& self
.type_params
.get(&def_id)
.map_or(false, |def| match def.kind {
GenericParamDefKind::Type { has_default, .. } => has_default,
_ => unreachable!(),
})
}
pub fn add_inherent_item(
&mut self,
parent_def_id: DefId,
kind: AssocKind,
name: Symbol,
impl_def_id: DefId,
item_def_id: DefId,
) {
self.inherent_items
.entry(InherentEntry {
parent_def_id,
kind,
name,
})
.or_insert_with(Default::default)
.insert((impl_def_id, item_def_id));
}
pub fn get_inherent_impls(&self, inherent_entry: &InherentEntry) -> Option<&InherentImplSet> {
self.inherent_items.get(inherent_entry)
}
pub fn get_new_id(&self, old: DefId) -> Option<DefId> {
assert!(!self.in_new_crate(old));
if self.in_old_crate(old) {
if let Some(new) = self.toplevel_mapping.get(&old) {
Some(new.1.def_id())
} else if let Some(new) = self.trait_item_mapping.get(&old) {
Some(new.1.def_id())
} else {
self.internal_mapping.get(&old).copied()
}
} else {
Some(old)
}
}
pub fn get_old_id(&self, new: DefId) -> Option<DefId> {
assert!(!self.in_old_crate(new));
if self.in_new_crate(new) {
self.reverse_mapping.get(&new).cloned()
} else {
Some(new)
}
}
pub fn get_trait_def(&self, item_def_id: DefId) -> Option<DefId> {
self.trait_item_mapping.get(&item_def_id).map(|t| t.2)
}
pub fn is_private_trait(&self, trait_def_id: DefId) -> bool {
self.private_traits.contains(&trait_def_id)
}
pub fn contains_old_id(&self, old: DefId) -> bool {
self.toplevel_mapping.contains_key(&old)
|| self.trait_item_mapping.contains_key(&old)
|| self.internal_mapping.contains_key(&old)
}
pub fn contains_new_id(&self, new: DefId) -> bool {
self.reverse_mapping.contains_key(&new)
}
pub fn toplevel_queue(&self) -> VecDeque<(Res, Res)> {
self.toplevel_mapping.values().copied().collect()
}
pub fn items(&self) -> impl Iterator<Item = (Res, Res)> + '_ {
self.toplevel_mapping
.values()
.cloned()
.chain(self.trait_item_mapping.values().map(|&(o, n, _)| (o, n)))
}
pub fn children_of(&self, parent: DefId) -> Option<impl Iterator<Item = (DefId, DefId)> + '_> {
self.child_mapping
.get(&parent)
.map(|m| m.iter().map(move |old| (*old, self.internal_mapping[old])))
}
pub fn inherent_impls(&self) -> impl Iterator<Item = (&InherentEntry, &InherentImplSet)> {
self.inherent_items.iter()
}
pub fn in_old_crate(&self, did: DefId) -> bool {
self.old_crate == did.krate
}
pub fn get_old_crate(&self) -> CrateNum {
self.old_crate
}
pub fn in_new_crate(&self, did: DefId) -> bool {
self.new_crate == did.krate
}
pub fn get_new_crate(&self) -> CrateNum {
self.new_crate
}
}
type OptionalExport = Option<ModChild>;
#[derive(Default)]
#[allow(clippy::module_name_repetitions)]
pub struct NameMapping {
type_map: HashMap<Symbol, (OptionalExport, OptionalExport)>,
value_map: HashMap<Symbol, (OptionalExport, OptionalExport)>,
macro_map: HashMap<Symbol, (OptionalExport, OptionalExport)>,
}
impl NameMapping {
fn insert(&mut self, item: ModChild, old: bool) {
use rustc_hir::def::DefKind::*;
use rustc_hir::def::Res::*;
let map = match item.res.expect_non_local::<HirId>() {
Def(kind, _) => match kind {
Mod |
Struct |
Union |
Enum |
Variant |
Trait |
TyAlias |
ForeignTy |
TraitAlias | AssocTy |
TyParam |
OpaqueTy => Some(&mut self.type_map),
Fn |
Const |
ConstParam |
Static(_) |
Ctor(_, _) |
AssocFn |
AssocConst => Some(&mut self.value_map),
Macro(_) => Some(&mut self.macro_map),
ExternCrate |
Use |
ForeignMod |
AnonConst |
InlineConst |
Field |
LifetimeParam |
GlobalAsm |
Impl |
Closure |
Generator => None,
},
PrimTy(_) | SelfTy { .. } => Some(&mut self.type_map),
SelfCtor(_) | Local(_) => Some(&mut self.value_map),
_ => None,
};
if let Some(map) = map {
if old {
map.entry(item.ident.name).or_insert((None, None)).0 = Some(item);
} else {
map.entry(item.ident.name).or_insert((None, None)).1 = Some(item);
};
}
}
pub fn add(&mut self, old_items: Vec<ModChild>, new_items: Vec<ModChild>) {
for item in old_items {
self.insert(item, true);
}
for item in new_items {
self.insert(item, false);
}
}
pub fn drain(&mut self) -> impl Iterator<Item = (Option<ModChild>, Option<ModChild>)> + '_ {
self.type_map
.drain()
.chain(self.value_map.drain())
.chain(self.macro_map.drain())
.map(|t| t.1)
}
}