forge_doc/preprocessor/
contract_inheritance.rsuse super::{Preprocessor, PreprocessorId};
use crate::{document::DocumentContent, Document, ParseSource, PreprocessorOutput};
use alloy_primitives::map::HashMap;
use forge_fmt::solang_ext::SafeUnwrap;
use std::path::PathBuf;
pub const CONTRACT_INHERITANCE_ID: PreprocessorId = PreprocessorId("contract_inheritance");
#[derive(Debug, Default)]
pub struct ContractInheritance {
pub include_libraries: bool,
}
impl Preprocessor for ContractInheritance {
fn id(&self) -> PreprocessorId {
CONTRACT_INHERITANCE_ID
}
fn preprocess(&self, documents: Vec<Document>) -> Result<Vec<Document>, eyre::Error> {
for document in documents.iter() {
if let DocumentContent::Single(ref item) = document.content {
if let ParseSource::Contract(ref contract) = item.source {
let mut links = HashMap::default();
for base in contract.base.iter() {
let base_ident = base.name.identifiers.last().unwrap().name.clone();
if let Some(linked) = self.try_link_base(&base_ident, &documents) {
links.insert(base_ident, linked);
}
}
if !links.is_empty() {
document
.add_context(self.id(), PreprocessorOutput::ContractInheritance(links));
}
}
}
}
Ok(documents)
}
}
impl ContractInheritance {
fn try_link_base(&self, base: &str, documents: &Vec<Document>) -> Option<PathBuf> {
for candidate in documents {
if candidate.from_library && !self.include_libraries {
continue;
}
if let DocumentContent::Single(ref item) = candidate.content {
if let ParseSource::Contract(ref contract) = item.source {
if base == contract.name.safe_unwrap().name {
return Some(candidate.target_path.clone())
}
}
}
}
None
}
}