#![allow(dead_code)]
use log::debug;
use log_derive::{logfn, logfn_inputs};
use rustc_hir::def_id::DefId;
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_hir::{ItemKind, Node};
use rustc_middle::ty::print::{FmtPrinter, Printer};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TyKind};
use std::rc::Rc;
#[logfn_inputs(TRACE)]
pub fn find_sysroot() -> String {
let home = option_env!("RUSTUP_HOME");
let toolchain = option_env!("RUSTUP_TOOLCHAIN");
match (home, toolchain) {
(Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
_ => option_env!("RUST_SYSROOT")
.expect(
"Could not find sysroot. Specify the RUST_SYSROOT environment variable, \
or use rustup to set the compiler to use for Mirai",
)
.to_owned(),
}
}
#[logfn(TRACE)]
pub fn is_public(def_id: DefId, tcx: TyCtxt<'_>) -> bool {
if let Some(node) = tcx.hir().get_if_local(def_id) {
match node {
Node::Expr(rustc_hir::Expr {
kind: rustc_hir::ExprKind::Closure(..),
..
}) => {
if let Some(parent_def_id) = tcx.parent(def_id) {
is_public(parent_def_id, tcx)
} else {
false
}
}
Node::Item(item) => match item.kind {
ItemKind::Fn(..) | ItemKind::Const(..) | ItemKind::Static(..) => {
item.vis.node.is_pub()
}
_ => {
debug!("def_id is unsupported item kind {:?}", item.kind);
false
}
},
Node::ImplItem(item) => item.vis.node.is_pub(),
Node::TraitItem(..) => true,
Node::AnonConst(..) => false,
_ => {
debug!("def_id is not an item {:?}", node);
false
}
}
} else {
false
}
}
#[logfn(TRACE)]
pub fn argument_types_key_str<'tcx>(
tcx: TyCtxt<'tcx>,
generic_args: SubstsRef<'tcx>,
) -> Rc<String> {
let mut result = "_".to_string();
for generic_ty_arg in generic_args.types() {
result.push('_');
append_mangled_type(&mut result, generic_ty_arg, tcx);
}
Rc::new(result)
}
#[logfn(TRACE)]
fn append_mangled_type<'tcx>(str: &mut String, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) {
use TyKind::*;
match ty.kind() {
Bool => str.push_str("bool"),
Char => str.push_str("char"),
Int(int_ty) => {
str.push_str(match int_ty {
ty::IntTy::Isize => "isize",
ty::IntTy::I8 => "i8",
ty::IntTy::I16 => "i16",
ty::IntTy::I32 => "i32",
ty::IntTy::I64 => "i64",
ty::IntTy::I128 => "i128",
});
}
Uint(uint_ty) => {
str.push_str(match uint_ty {
ty::UintTy::Usize => "usize",
ty::UintTy::U8 => "u8",
ty::UintTy::U16 => "u16",
ty::UintTy::U32 => "u32",
ty::UintTy::U64 => "u64",
ty::UintTy::U128 => "u128",
});
}
Float(float_ty) => {
str.push_str(match float_ty {
ty::FloatTy::F32 => "f32",
ty::FloatTy::F64 => "f64",
});
}
Adt(def, subs) => {
str.push_str(qualified_type_name(tcx, def.did).as_str());
for sub in *subs {
if let GenericArgKind::Type(ty) = sub.unpack() {
str.push('_');
append_mangled_type(str, ty, tcx);
}
}
}
Closure(def_id, subs) => {
str.push_str("closure_");
str.push_str(qualified_type_name(tcx, *def_id).as_str());
for sub in subs.as_closure().substs {
if let GenericArgKind::Type(ty) = sub.unpack() {
str.push('_');
append_mangled_type(str, ty, tcx);
}
}
}
Dynamic(..) => str.push_str(&format!("dyn_{:?}", ty)),
Foreign(def_id) => {
str.push_str("extern_type_");
str.push_str(qualified_type_name(tcx, *def_id).as_str());
}
FnDef(def_id, subs) => {
str.push_str("fn_");
str.push_str(qualified_type_name(tcx, *def_id).as_str());
for sub in *subs {
if let GenericArgKind::Type(ty) = sub.unpack() {
str.push('_');
append_mangled_type(str, ty, tcx);
}
}
}
Generator(def_id, subs, ..) => {
str.push_str("generator_");
str.push_str(qualified_type_name(tcx, *def_id).as_str());
for sub in subs.as_generator().substs {
if let GenericArgKind::Type(ty) = sub.unpack() {
str.push('_');
append_mangled_type(str, ty, tcx);
}
}
}
GeneratorWitness(binder) => {
for ty in binder.skip_binder().iter() {
str.push('_');
append_mangled_type(str, ty, tcx)
}
}
Opaque(def_id, subs) => {
str.push_str("impl_");
str.push_str(qualified_type_name(tcx, *def_id).as_str());
for sub in *subs {
if let GenericArgKind::Type(ty) = sub.unpack() {
str.push('_');
append_mangled_type(str, ty, tcx);
}
}
}
Str => str.push_str("str"),
Array(ty, _) => {
str.push_str("array_");
append_mangled_type(str, ty, tcx);
}
Slice(ty) => {
str.push_str("slice_");
append_mangled_type(str, ty, tcx);
}
RawPtr(ty_and_mut) => {
str.push_str("pointer_");
match ty_and_mut.mutbl {
rustc_hir::Mutability::Mut => str.push_str("mut_"),
rustc_hir::Mutability::Not => str.push_str("const_"),
}
append_mangled_type(str, ty_and_mut.ty, tcx);
}
Ref(_, ty, mutability) => {
str.push_str("ref_");
if *mutability == rustc_hir::Mutability::Mut {
str.push_str("mut_");
}
append_mangled_type(str, ty, tcx);
}
FnPtr(poly_fn_sig) => {
let fn_sig = poly_fn_sig.skip_binder();
str.push_str("fn_ptr_");
for arg_type in fn_sig.inputs() {
append_mangled_type(str, arg_type, tcx);
str.push_str("_");
}
append_mangled_type(str, fn_sig.output(), tcx);
}
Tuple(types) => {
str.push_str("tuple_");
str.push_str(&format!("{}", types.len()));
types.iter().for_each(|t| {
str.push('_');
append_mangled_type(str, t.expect_ty(), tcx);
});
}
Param(param_ty) => {
let pty: Ty<'tcx> = param_ty.to_ty(tcx);
if ty.eq(pty) {
str.push_str(&format!("{:?}", ty));
} else {
append_mangled_type(str, pty, tcx);
}
}
Projection(projection_ty) => {
append_mangled_type(str, projection_ty.self_ty(), tcx);
str.push_str("_as_");
str.push_str(qualified_type_name(tcx, projection_ty.item_def_id).as_str());
}
_ => {
debug!("{:?}", ty);
debug!("{:?}", ty.kind());
str.push_str(&format!("default formatted {:?}", ty))
}
}
}
#[logfn(TRACE)]
fn qualified_type_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
let mut name = crate_name(tcx, def_id);
for component in &tcx.def_path(def_id).data {
name.push('_');
push_component_name(component.data, &mut name);
if component.disambiguator != 0 {
name.push('_');
let da = component.disambiguator.to_string();
name.push_str(da.as_str());
}
}
name
}
#[logfn(TRACE)]
fn crate_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
tcx.crate_name(def_id.krate).as_str().to_string()
}
#[logfn(TRACE)]
pub fn summary_key_str(tcx: TyCtxt<'_>, def_id: DefId) -> Rc<String> {
let mut name = crate_name(tcx, def_id);
let mut type_ns: Option<String> = None;
for component in &tcx.def_path(def_id).data {
if name.ends_with("foreign_contracts") {
name.clear();
} else {
name.push('.');
}
push_component_name(component.data, &mut name);
if let DefPathData::TypeNs(sym) = component.data {
type_ns = Some(sym.as_str().to_string());
}
if component.disambiguator != 0 {
name.push('_');
if component.data == DefPathData::Impl {
if let Some(parent_def_id) = tcx.parent(def_id) {
if let Some(type_ns) = &type_ns {
let def_kind = tcx.def_kind(parent_def_id);
use rustc_hir::def::DefKind::*;
if type_ns == "num"
&& (def_kind == Struct || def_kind == Union || def_kind == Enum)
{
append_mangled_type(&mut name, tcx.type_of(parent_def_id), tcx);
continue;
}
}
}
if let Some(type_ns) = &type_ns {
name.push_str(&type_ns);
continue;
}
}
let da = component.disambiguator.to_string();
name.push_str(da.as_str());
}
}
Rc::new(name)
}
pub fn is_foreign_contract(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(DisambiguatedDefPathData {
data: DefPathData::TypeNs(name),
..
}) = &tcx.def_path(def_id).data.first()
{
name.as_str() == "foreign_contracts"
} else {
false
}
}
fn push_component_name(component_data: DefPathData, target: &mut String) {
use std::ops::Deref;
use DefPathData::*;
match component_data {
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => {
target.push_str(name.as_str().deref());
}
_ => target.push_str(match component_data {
CrateRoot => "crate_root",
Impl => "implement",
Misc => "miscellaneous",
ClosureExpr => "closure",
Ctor => "ctor",
AnonConst => "constant",
ImplTrait => "implement_trait",
_ => unreachable!(),
}),
};
}
pub fn def_id_display_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
struct PrettyDefId<'tcx>(DefId, TyCtxt<'tcx>);
impl std::fmt::Debug for PrettyDefId<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FmtPrinter::new(self.1, f, rustc_hir::def::Namespace::ValueNS)
.print_def_path(self.0, &[])?;
Ok(())
}
}
format!("{:?}", PrettyDefId(def_id, tcx))
}