use crate::codegen::doc_emission::emit_c_doxygen;
use crate::core::ir::{FunctionDef, MethodDef, TypeRef};
pub(super) fn ffi_doxygen_block(doc: &str) -> String {
let mut full_doc = String::with_capacity(doc.len() + 128);
if !doc.is_empty() {
full_doc.push_str(doc);
if !doc.contains("# Safety") {
full_doc.push_str(
"\n\n# Safety\n\nCaller must ensure all pointer arguments are valid or null. \
Returned pointers must be freed with the appropriate free function.",
);
}
} else {
full_doc.push_str(
"# Safety\n\nCaller must ensure all pointer arguments are valid or null. \
Returned pointers must be freed with the appropriate free function.",
);
}
let mut out = String::new();
emit_c_doxygen(&mut out, &full_doc, "");
out
}
pub(super) fn sanitized_recoverable(func: &FunctionDef) -> bool {
let params_ok = func.params.iter().all(|p| {
if !p.sanitized {
return true;
}
p.original_type.is_some() && matches!(&p.ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::String))
});
if !params_ok {
return false;
}
let any_param_sanitized = func.params.iter().any(|p| p.sanitized);
!func.sanitized || any_param_sanitized
}
pub(super) fn method_sanitized_recoverable(method: &MethodDef) -> bool {
let params_ok = method.params.iter().all(|p| {
if !p.sanitized {
return true;
}
p.original_type.is_some() && matches!(&p.ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::String))
});
if !params_ok {
return false;
}
let any_param_sanitized = method.params.iter().any(|p| p.sanitized);
!method.sanitized || any_param_sanitized
}