use std::{cmp::Ordering, fmt};
use hir::db::HirDatabase;
use ra_ap_hir::{self as hir, HasVisibility as _};
use ra_ap_ide::Edition;
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ItemVisibility {
Crate,
Module(String),
Private,
Public,
Super,
}
impl ItemVisibility {
pub fn new(hir: hir::ModuleDef, db: &dyn HirDatabase, edition: Edition) -> Self {
let visibility = hir.visibility(db);
let parent_module = match hir.module(db) {
Some(module) => module,
None => return Self::Public,
};
let grandparent_module = parent_module.parent(db);
let krate_module = parent_module.krate(db).root_module(db);
match visibility {
hir::Visibility::Module(visibility_module_id, _visibility_explicity) => {
let visibility_module = hir::Module::from(visibility_module_id);
if visibility_module == krate_module {
Self::Crate
} else if Some(visibility_module) == grandparent_module {
Self::Super
} else if visibility_module == parent_module {
Self::Private
} else {
let visibility_module_def_hir = hir::ModuleDef::Module(visibility_module);
let path = visibility_module_def_hir
.canonical_path(db, edition)
.unwrap();
Self::Module(path)
}
}
hir::Visibility::PubCrate(_) => Self::Crate,
hir::Visibility::Public => Self::Public,
}
}
fn numerical_order(&self) -> isize {
match self {
ItemVisibility::Public => 0,
ItemVisibility::Crate => 1,
ItemVisibility::Module(_) => 2,
ItemVisibility::Super => 3,
ItemVisibility::Private => 4,
}
}
}
impl PartialOrd for ItemVisibility {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ItemVisibility {
fn cmp(&self, other: &Self) -> Ordering {
match self.numerical_order().cmp(&other.numerical_order()) {
ord @ Ordering::Less => ord,
ord @ Ordering::Equal => match (self, other) {
(ItemVisibility::Module(lhs), ItemVisibility::Module(rhs)) => lhs.cmp(rhs),
_ => ord,
},
ord @ Ordering::Greater => ord,
}
}
}
impl fmt::Display for ItemVisibility {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ItemVisibility::Crate => write!(f, "pub(crate)"),
ItemVisibility::Module(path) => write!(f, "pub(in crate::{path})"),
ItemVisibility::Private => write!(f, "pub(self)"),
ItemVisibility::Public => write!(f, "pub"),
ItemVisibility::Super => write!(f, "pub(super)"),
}
}
}