rapx 0.7.40

A static analysis platform for Rust program analysis and verification
use rustc_hir::{Node::*, def::DefKind};
use rustc_middle::ty::TyCtxt;
use rustc_span::{FileName, def_id::DefId, symbol::Symbol};

pub fn get_fn_name(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String> {
    let name = tcx.def_path(def_id).to_string_no_crate_verbose();
    Some(name)
}

pub fn get_fn_name_byid(def_id: &DefId) -> String {
    let s = format!("{:?}", *def_id);
    if let Some(start) = s.find("DefId") {
        if let Some(end) = s.find("]::") {
            let s1 = s.replace(&s[start..end + 3], "").to_string();
            if let Some(start) = s1.find(")") {
                let result = s1.replace(&s1[start..start + 1], "").to_string();
                return result;
            }
            return s1;
        }
    }
    s.clone()
}
pub fn get_name(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
    if def_id.is_local() {
        if let Some(node) = tcx.hir_get_if_local(def_id) {
            match node {
                Item(item) => {
                    let ident = tcx.hir_ident(item.hir_id());
                    return Some(ident.name);
                }
                ImplItem(item) => {
                    let ident = tcx.hir_ident(item.hir_id());
                    return Some(ident.name);
                }
                ForeignItem(item) => {
                    let ident = tcx.hir_ident(item.hir_id());
                    return Some(ident.name);
                }
                TraitItem(item) => {
                    let ident = tcx.hir_ident(item.hir_id());
                    return Some(ident.name);
                }
                _ => {
                    return None;
                }
            }
        }
    }
    None
}

pub fn get_filename(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String> {
    // Get the HIR node corresponding to the DefId
    let local_id = def_id.as_local()?;
    let hir_id = tcx.local_def_id_to_hir_id(local_id);
    let span = tcx.hir_span(hir_id);

    // Retrieve the file name
    let filename = tcx.sess.source_map().span_to_filename(span);
    match filename {
        FileName::Real(realname) => realname
            .local_path()
            .map(|path| path.to_string_lossy().into()),
        _ => None,
    }
}

pub fn get_module_name(tcx: TyCtxt, def_id: DefId) -> String {
    // --- external items ---
    if !def_id.is_local() {
        return tcx.def_path_str(def_id);
    }

    let local = def_id.as_local().unwrap();
    let mod_local = tcx.parent_module_from_def_id(local);
    let mod_id = mod_local.to_def_id();
    let path = tcx.def_path_str(mod_id);

    if path.is_empty() {
        "default".to_string()
    } else {
        path
    }
}

pub fn get_adt_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
    match tcx.def_kind(def_id) {
        DefKind::Struct | DefKind::Enum | DefKind::Union => {
            return strip_generic_args(&tcx.type_of(def_id).skip_binder().to_string());
        }
        _ => {}
    }
    if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
        if let Some(impl_id) = assoc_item.impl_container(tcx) {
            let ty = tcx.type_of(impl_id).skip_binder();
            return strip_generic_args(&ty.to_string());
        }
    }
    "Free_Functions".to_string()
}

/// Strip the generic-argument suffix (`<...>`) from a type name.
fn strip_generic_args(raw_name: &str) -> String {
    raw_name
        .split('<')
        .next()
        .unwrap_or(raw_name)
        .trim()
        .to_string()
}