forge_doc/preprocessor/
contract_inheritance.rs
1use super::{Preprocessor, PreprocessorId};
2use crate::{document::DocumentContent, Document, ParseSource, PreprocessorOutput};
3use alloy_primitives::map::HashMap;
4use forge_fmt::solang_ext::SafeUnwrap;
5use std::path::PathBuf;
6
7pub const CONTRACT_INHERITANCE_ID: PreprocessorId = PreprocessorId("contract_inheritance");
9
10#[derive(Debug, Default)]
18pub struct ContractInheritance {
19 pub include_libraries: bool,
21}
22
23impl Preprocessor for ContractInheritance {
24 fn id(&self) -> PreprocessorId {
25 CONTRACT_INHERITANCE_ID
26 }
27
28 fn preprocess(&self, documents: Vec<Document>) -> Result<Vec<Document>, eyre::Error> {
29 for document in &documents {
30 if let DocumentContent::Single(ref item) = document.content {
31 if let ParseSource::Contract(ref contract) = item.source {
32 let mut links = HashMap::default();
33
34 for base in &contract.base {
36 let base_ident = base.name.identifiers.last().unwrap().name.clone();
37 if let Some(linked) = self.try_link_base(&base_ident, &documents) {
38 links.insert(base_ident, linked);
39 }
40 }
41
42 if !links.is_empty() {
43 document
45 .add_context(self.id(), PreprocessorOutput::ContractInheritance(links));
46 }
47 }
48 }
49 }
50
51 Ok(documents)
52 }
53}
54
55impl ContractInheritance {
56 fn try_link_base(&self, base: &str, documents: &Vec<Document>) -> Option<PathBuf> {
57 for candidate in documents {
58 if candidate.from_library && !self.include_libraries {
59 continue;
60 }
61 if let DocumentContent::Single(ref item) = candidate.content {
62 if let ParseSource::Contract(ref contract) = item.source {
63 if base == contract.name.safe_unwrap().name {
64 return Some(candidate.target_path.clone())
65 }
66 }
67 }
68 }
69 None
70 }
71}