use crate::resolve::{ShapeExposure, strip_raw, type_to_string};
pub(crate) struct PathExposure {
pub(crate) seam: String,
pub(crate) path: syn::Path,
pub(crate) is_reexport: bool,
}
pub(crate) enum SemanticFinding {
Exposed { subject: String, seam: String },
MisplacedImpl { module: String, owner: String },
ForbiddenDerive { marker: String, canonical: String },
AsyncFreeFn {
module: String,
name: String,
tail: String,
},
AsyncTraitMethod {
module: String,
trait_name: String,
name: String,
tail: String,
},
AsyncInherentMethod {
owner: String,
name: String,
tail: String,
},
}
impl std::fmt::Display for SemanticFinding {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Exposed { subject, seam } => write!(f, "{subject} exposed by {seam}"),
Self::MisplacedImpl { module, owner } => write!(f, "{module} (impl for {owner})"),
Self::ForbiddenDerive { marker, canonical } => {
write!(f, "derive {marker} on {canonical}")
}
Self::AsyncFreeFn { module, name, tail } => {
write!(f, "async fn {module}::{name}{tail}")
}
Self::AsyncTraitMethod {
module,
trait_name,
name,
tail,
} => write!(f, "async fn trait {module}::{trait_name}::{name}{tail}"),
Self::AsyncInherentMethod { owner, name, tail } => {
write!(f, "async fn <{owner}>::{name}{tail}")
}
}
}
}
pub(crate) fn shape_finding(exposure: ShapeExposure) -> String {
SemanticFinding::Exposed {
subject: exposure.shape,
seam: exposure.seam,
}
.to_string()
}
pub(crate) fn tag_paths(paths: Vec<syn::Path>, seam: &str) -> Vec<PathExposure> {
paths
.into_iter()
.map(|path| PathExposure {
seam: seam.to_string(),
path,
is_reexport: false,
})
.collect()
}
pub(crate) fn fn_seam(module: &str, name: &syn::Ident) -> String {
format!("fn {module}::{}", strip_raw(&name.to_string()))
}
pub(crate) fn inherent_method_seam(owner: &str, name: &syn::Ident) -> String {
format!("fn <{owner}>::{}", strip_raw(&name.to_string()))
}
pub(crate) fn inherent_assoc_seam(kind: &str, owner: &str, name: &syn::Ident) -> String {
format!("{kind} <{owner}>::{}", strip_raw(&name.to_string()))
}
pub(crate) fn trait_method_seam(module: &str, trait_name: &str, name: &syn::Ident) -> String {
format!(
"fn trait {module}::{trait_name}::{}",
strip_raw(&name.to_string())
)
}
pub(crate) fn item_seam(kind: &str, module: &str, name: &syn::Ident) -> String {
format!("{kind} {module}::{}", strip_raw(&name.to_string()))
}
pub(crate) fn field_seam(kind: &str, module: &str, owner: &str, member: &str) -> String {
format!("{kind} {module}::{owner}::{member}")
}
pub(crate) fn trait_assoc_seam(
kind: &str,
module: &str,
trait_name: &str,
name: &syn::Ident,
) -> String {
format!(
"{kind} trait {module}::{trait_name}::{}",
strip_raw(&name.to_string())
)
}
pub(crate) fn member_label(index: usize, field: &syn::Field) -> String {
match &field.ident {
Some(ident) => strip_raw(&ident.to_string()),
None => index.to_string(),
}
}
pub(crate) fn render_sig_tail(sig: &syn::Signature) -> String {
let params: Vec<String> = sig
.inputs
.iter()
.map(|arg| match arg {
syn::FnArg::Receiver(receiver) => {
let reference = if receiver.reference.is_some() {
"&"
} else {
""
};
let mutability = if receiver.mutability.is_some() {
"mut "
} else {
""
};
format!("{reference}{mutability}self")
}
syn::FnArg::Typed(pat_type) => {
type_to_string(&pat_type.ty).unwrap_or_else(|| "_".to_string())
}
})
.collect();
let ret = match &sig.output {
syn::ReturnType::Type(_, ty) => {
format!(
" -> {}",
type_to_string(ty).unwrap_or_else(|| "_".to_string())
)
}
syn::ReturnType::Default => String::new(),
};
format!("({}){ret}", params.join(", "))
}