1use crate::{
12 sources::VersionedSourceFile, Artifact, ArtifactFile, ArtifactOutput, SolcConfig, SolcError,
13 SourceFile,
14};
15use alloy_json_abi::JsonAbi;
16use alloy_primitives::hex;
17use foundry_compilers_artifacts::{
18 bytecode::{CompactBytecode, CompactDeployedBytecode},
19 contract::Contract,
20 output_selection::{
21 BytecodeOutputSelection, ContractOutputSelection, DeployedBytecodeOutputSelection,
22 EvmOutputSelection, EwasmOutputSelection,
23 },
24 BytecodeObject, ConfigurableContractArtifact, Evm, Ewasm, GeneratedSource, LosslessMetadata,
25 Metadata, Settings,
26};
27use foundry_compilers_core::utils;
28use std::{fs, path::Path};
29
30#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
44pub struct ConfigurableArtifacts {
45 pub additional_values: ExtraOutputValues,
47
48 pub additional_files: ExtraOutputFiles,
50
51 #[doc(hidden)]
63 pub __non_exhaustive: (),
64}
65
66impl ConfigurableArtifacts {
67 pub fn new(
68 extra_values: impl IntoIterator<Item = ContractOutputSelection>,
69 extra_files: impl IntoIterator<Item = ContractOutputSelection>,
70 ) -> Self {
71 Self {
72 additional_values: ExtraOutputValues::from_output_selection(extra_values),
73 additional_files: ExtraOutputFiles::from_output_selection(extra_files),
74 ..Default::default()
75 }
76 }
77
78 pub fn solc_settings(&self) -> Settings {
80 SolcConfig::builder()
81 .additional_outputs(self.output_selection())
82 .ast(self.additional_values.ast)
83 .build()
84 }
85
86 pub fn output_selection(&self) -> Vec<ContractOutputSelection> {
88 let mut selection = ContractOutputSelection::basic();
89
90 let ExtraOutputValues {
91 ast: _,
93 userdoc,
94 devdoc,
95 method_identifiers,
96 storage_layout,
97 transient_storage_layout,
98 assembly,
99 legacy_assembly,
100 gas_estimates,
101 metadata,
102 ir,
103 ir_optimized,
104 ir_optimized_ast,
105 ewasm,
106 function_debug_data,
107 generated_sources,
108 source_map,
109 opcodes,
110 __non_exhaustive,
111 } = self.additional_values;
112
113 if ir || self.additional_files.ir {
114 selection.push(ContractOutputSelection::Ir);
115 }
116 if ir_optimized || self.additional_files.ir_optimized {
117 selection.push(ContractOutputSelection::IrOptimized);
118 }
119 if metadata || self.additional_files.metadata {
120 selection.push(ContractOutputSelection::Metadata);
121 }
122 if storage_layout {
123 selection.push(ContractOutputSelection::StorageLayout);
124 }
125 if devdoc {
126 selection.push(ContractOutputSelection::DevDoc);
127 }
128 if userdoc {
129 selection.push(ContractOutputSelection::UserDoc);
130 }
131 if gas_estimates {
132 selection.push(EvmOutputSelection::GasEstimates.into());
133 }
134 if assembly || self.additional_files.assembly {
135 selection.push(EvmOutputSelection::Assembly.into());
136 }
137 if legacy_assembly || self.additional_files.legacy_assembly {
138 selection.push(EvmOutputSelection::LegacyAssembly.into());
139 }
140 if ewasm || self.additional_files.ewasm {
141 selection.push(EwasmOutputSelection::All.into());
142 }
143 if function_debug_data {
144 selection.push(BytecodeOutputSelection::FunctionDebugData.into());
145 }
146 if method_identifiers {
147 selection.push(EvmOutputSelection::MethodIdentifiers.into());
148 }
149 if generated_sources {
150 selection.push(
151 EvmOutputSelection::ByteCode(BytecodeOutputSelection::GeneratedSources).into(),
152 );
153 }
154 if source_map {
155 selection.push(EvmOutputSelection::ByteCode(BytecodeOutputSelection::SourceMap).into());
156 }
157 if ir_optimized_ast {
158 selection.push(ContractOutputSelection::IrOptimizedAst);
159 }
160 if opcodes {
161 selection.push(EvmOutputSelection::ByteCode(BytecodeOutputSelection::Opcodes).into());
162 }
163 if transient_storage_layout {
164 selection.push(ContractOutputSelection::TransientStorageLayout);
165 }
166 selection
167 }
168}
169
170impl ArtifactOutput for ConfigurableArtifacts {
171 type Artifact = ConfigurableContractArtifact;
172 type CompilerContract = Contract;
173
174 fn handle_artifacts(
176 &self,
177 contracts: &crate::VersionedContracts<Contract>,
178 artifacts: &crate::Artifacts<Self::Artifact>,
179 ) -> Result<(), SolcError> {
180 for (file, contracts) in contracts.as_ref().iter() {
181 for (name, versioned_contracts) in contracts {
182 for contract in versioned_contracts {
183 if let Some(artifact) = artifacts.find_artifact(file, name, &contract.version) {
184 let file = &artifact.file;
185 utils::create_parent_dir_all(file)?;
186 self.additional_files.write_extras(&contract.contract, file)?;
187 }
188 }
189 }
190 }
191 Ok(())
192 }
193
194 fn contract_to_artifact(
195 &self,
196 _file: &Path,
197 _name: &str,
198 contract: Contract,
199 source_file: Option<&SourceFile>,
200 ) -> Self::Artifact {
201 let mut artifact_userdoc = None;
202 let mut artifact_devdoc = None;
203 let mut artifact_raw_metadata = None;
204 let mut artifact_metadata = None;
205 let mut artifact_ir = None;
206 let mut artifact_ir_optimized = None;
207 let mut artifact_ir_optimized_ast = None;
208 let mut artifact_ewasm = None;
209 let mut artifact_bytecode = None;
210 let mut artifact_deployed_bytecode = None;
211 let mut artifact_gas_estimates = None;
212 let mut artifact_function_debug_data = None;
213 let mut artifact_method_identifiers = None;
214 let mut artifact_assembly = None;
215 let mut artifact_legacy_assembly = None;
216 let mut artifact_storage_layout = None;
217 let mut artifact_transient_storage_layout = None;
218 let mut generated_sources = None;
219 let mut opcodes = None;
220
221 let Contract {
222 abi,
223 metadata,
224 userdoc,
225 devdoc,
226 ir,
227 storage_layout,
228 transient_storage_layout,
229 evm,
230 ewasm,
231 ir_optimized,
232 ir_optimized_ast,
233 } = contract;
234
235 if self.additional_values.metadata {
236 if let Some(LosslessMetadata { raw_metadata, metadata }) = metadata {
237 artifact_raw_metadata = Some(raw_metadata);
238 artifact_metadata = Some(metadata);
239 }
240 }
241 if self.additional_values.userdoc {
242 artifact_userdoc = Some(userdoc);
243 }
244 if self.additional_values.devdoc {
245 artifact_devdoc = Some(devdoc);
246 }
247 if self.additional_values.ewasm {
248 artifact_ewasm = ewasm;
249 }
250 if self.additional_values.ir {
251 artifact_ir = ir;
252 }
253 if self.additional_values.ir_optimized {
254 artifact_ir_optimized = ir_optimized;
255 }
256 if self.additional_values.ir_optimized_ast {
257 artifact_ir_optimized_ast = ir_optimized_ast;
258 }
259 if self.additional_values.storage_layout {
260 artifact_storage_layout = Some(storage_layout);
261 }
262 if self.additional_values.transient_storage_layout {
263 artifact_transient_storage_layout = Some(transient_storage_layout);
264 }
265
266 if let Some(evm) = evm {
267 let Evm {
268 assembly,
269 mut bytecode,
270 deployed_bytecode,
271 method_identifiers,
272 gas_estimates,
273 legacy_assembly,
274 } = evm;
275
276 if self.additional_values.function_debug_data {
277 artifact_function_debug_data =
278 bytecode.as_mut().map(|code| std::mem::take(&mut code.function_debug_data));
279 }
280 if self.additional_values.generated_sources {
281 generated_sources =
282 bytecode.as_mut().map(|code| std::mem::take(&mut code.generated_sources));
283 }
284
285 if self.additional_values.opcodes {
286 opcodes = bytecode.as_mut().and_then(|code| code.opcodes.take())
287 }
288
289 artifact_bytecode = bytecode.map(Into::into);
290 artifact_deployed_bytecode = deployed_bytecode.map(Into::into);
291 artifact_method_identifiers = Some(method_identifiers);
292
293 if self.additional_values.gas_estimates {
294 artifact_gas_estimates = gas_estimates;
295 }
296 if self.additional_values.assembly {
297 artifact_assembly = assembly;
298 }
299
300 if self.additional_values.legacy_assembly {
301 artifact_legacy_assembly = legacy_assembly;
302 }
303 }
304
305 ConfigurableContractArtifact {
306 abi,
307 bytecode: artifact_bytecode,
308 deployed_bytecode: artifact_deployed_bytecode,
309 assembly: artifact_assembly,
310 legacy_assembly: artifact_legacy_assembly,
311 opcodes,
312 function_debug_data: artifact_function_debug_data,
313 method_identifiers: artifact_method_identifiers,
314 gas_estimates: artifact_gas_estimates,
315 raw_metadata: artifact_raw_metadata,
316 metadata: artifact_metadata,
317 storage_layout: artifact_storage_layout,
318 transient_storage_layout: artifact_transient_storage_layout,
319 userdoc: artifact_userdoc,
320 devdoc: artifact_devdoc,
321 ir: artifact_ir,
322 ir_optimized: artifact_ir_optimized,
323 ir_optimized_ast: artifact_ir_optimized_ast,
324 ewasm: artifact_ewasm,
325 id: source_file.as_ref().map(|s| s.id),
326 ast: source_file.and_then(|s| s.ast.clone()),
327 generated_sources: generated_sources.unwrap_or_default(),
328 }
329 }
330
331 fn standalone_source_file_to_artifact(
332 &self,
333 _path: &Path,
334 file: &VersionedSourceFile,
335 ) -> Option<Self::Artifact> {
336 file.source_file.ast.clone().map(|ast| ConfigurableContractArtifact {
337 abi: Some(JsonAbi::default()),
338 id: Some(file.source_file.id),
339 ast: Some(ast),
340 bytecode: Some(CompactBytecode::empty()),
341 deployed_bytecode: Some(CompactDeployedBytecode::empty()),
342 ..Default::default()
343 })
344 }
345
346 fn is_dirty(&self, artifact_file: &ArtifactFile<Self::Artifact>) -> Result<bool, SolcError> {
349 let artifact = &artifact_file.artifact;
350 let ExtraOutputFiles {
351 abi: _,
352 metadata,
353 ir,
354 ir_optimized,
355 ewasm,
356 assembly,
357 legacy_assembly,
358 source_map,
359 generated_sources,
360 bytecode: _,
361 deployed_bytecode: _,
362 __non_exhaustive: _,
363 } = self.additional_files;
364
365 if metadata && artifact.metadata.is_none() {
366 return Ok(true);
367 }
368 if ir && artifact.ir.is_none() {
369 return Ok(true);
370 }
371 if ir_optimized && artifact.ir_optimized.is_none() {
372 return Ok(true);
373 }
374 if ewasm && artifact.ewasm.is_none() {
375 return Ok(true);
376 }
377 if assembly && artifact.assembly.is_none() {
378 return Ok(true);
379 }
380 if assembly && artifact.assembly.is_none() {
381 return Ok(true);
382 }
383 if legacy_assembly && artifact.legacy_assembly.is_none() {
384 return Ok(true);
385 }
386 if source_map && artifact.get_source_map_str().is_none() {
387 return Ok(true);
388 }
389 if generated_sources {
390 return Ok(true);
392 }
393 Ok(false)
394 }
395
396 fn handle_cached_artifacts(
398 &self,
399 artifacts: &crate::Artifacts<Self::Artifact>,
400 ) -> Result<(), SolcError> {
401 for artifacts in artifacts.values() {
402 for artifacts in artifacts.values() {
403 for artifact_file in artifacts {
404 let file = &artifact_file.file;
405 let artifact = &artifact_file.artifact;
406 self.additional_files.process_abi(artifact.abi.as_ref(), file)?;
407 self.additional_files.process_assembly(artifact.assembly.as_deref(), file)?;
408 self.additional_files
409 .process_legacy_assembly(artifact.legacy_assembly.clone(), file)?;
410 self.additional_files
411 .process_bytecode(artifact.bytecode.as_ref().map(|b| &b.object), file)?;
412 self.additional_files.process_deployed_bytecode(
413 artifact
414 .deployed_bytecode
415 .as_ref()
416 .and_then(|d| d.bytecode.as_ref())
417 .map(|b| &b.object),
418 file,
419 )?;
420 self.additional_files
421 .process_generated_sources(Some(&artifact.generated_sources), file)?;
422 self.additional_files.process_ir(artifact.ir.as_deref(), file)?;
423 self.additional_files
424 .process_ir_optimized(artifact.ir_optimized.as_deref(), file)?;
425 self.additional_files.process_ewasm(artifact.ewasm.as_ref(), file)?;
426 self.additional_files.process_metadata(artifact.metadata.as_ref(), file)?;
427 self.additional_files
428 .process_source_map(artifact.get_source_map_str().as_deref(), file)?;
429 }
430 }
431 }
432
433 Ok(())
434 }
435}
436
437#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
439pub struct ExtraOutputValues {
440 pub ast: bool,
441 pub userdoc: bool,
442 pub devdoc: bool,
443 pub method_identifiers: bool,
444 pub storage_layout: bool,
445 pub transient_storage_layout: bool,
446 pub assembly: bool,
447 pub legacy_assembly: bool,
448 pub gas_estimates: bool,
449 pub metadata: bool,
450 pub ir: bool,
451 pub ir_optimized: bool,
452 pub ir_optimized_ast: bool,
453 pub ewasm: bool,
454 pub function_debug_data: bool,
455 pub generated_sources: bool,
456 pub source_map: bool,
457 pub opcodes: bool,
458
459 #[doc(hidden)]
468 pub __non_exhaustive: (),
469}
470
471impl ExtraOutputValues {
472 pub fn all() -> Self {
474 Self {
475 ast: true,
476 userdoc: true,
477 devdoc: true,
478 method_identifiers: true,
479 storage_layout: true,
480 transient_storage_layout: true,
481 assembly: true,
482 legacy_assembly: true,
483 gas_estimates: true,
484 metadata: true,
485 ir: true,
486 ir_optimized: true,
487 ir_optimized_ast: true,
488 ewasm: true,
489 function_debug_data: true,
490 generated_sources: true,
491 source_map: true,
492 opcodes: true,
493 __non_exhaustive: (),
494 }
495 }
496
497 pub fn from_output_selection(
499 settings: impl IntoIterator<Item = ContractOutputSelection>,
500 ) -> Self {
501 let mut config = Self::default();
502 for value in settings.into_iter() {
503 match value {
504 ContractOutputSelection::DevDoc => {
505 config.devdoc = true;
506 }
507 ContractOutputSelection::UserDoc => {
508 config.userdoc = true;
509 }
510 ContractOutputSelection::Metadata => {
511 config.metadata = true;
512 }
513 ContractOutputSelection::Ir => {
514 config.ir = true;
515 }
516 ContractOutputSelection::IrOptimized => {
517 config.ir_optimized = true;
518 }
519 ContractOutputSelection::StorageLayout => {
520 config.storage_layout = true;
521 }
522 ContractOutputSelection::Evm(evm) => match evm {
523 EvmOutputSelection::All => {
524 config.assembly = true;
525 config.legacy_assembly = true;
526 config.gas_estimates = true;
527 config.method_identifiers = true;
528 config.generated_sources = true;
529 config.source_map = true;
530 config.opcodes = true;
531 }
532 EvmOutputSelection::Assembly => {
533 config.assembly = true;
534 }
535 EvmOutputSelection::LegacyAssembly => {
536 config.legacy_assembly = true;
537 }
538 EvmOutputSelection::MethodIdentifiers => {
539 config.method_identifiers = true;
540 }
541 EvmOutputSelection::GasEstimates => {
542 config.gas_estimates = true;
543 }
544 EvmOutputSelection::ByteCode(BytecodeOutputSelection::FunctionDebugData) => {
545 config.function_debug_data = true;
546 }
547 EvmOutputSelection::ByteCode(BytecodeOutputSelection::Opcodes) => {
548 config.opcodes = true;
549 }
550 EvmOutputSelection::ByteCode(BytecodeOutputSelection::GeneratedSources) => {
551 config.generated_sources = true;
552 }
553 EvmOutputSelection::ByteCode(BytecodeOutputSelection::SourceMap) => {
554 config.source_map = true;
555 }
556 _ => {}
557 },
558 ContractOutputSelection::Ewasm(_) => {
559 config.ewasm = true;
560 }
561 ContractOutputSelection::IrOptimizedAst => {
562 config.ir_optimized_ast = true;
563 }
564 ContractOutputSelection::TransientStorageLayout => {
565 config.transient_storage_layout = true;
566 }
567 ContractOutputSelection::Abi => {}
568 }
569 }
570
571 config
572 }
573}
574
575#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
577pub struct ExtraOutputFiles {
578 pub abi: bool,
579 pub metadata: bool,
580 pub ir: bool,
581 pub ir_optimized: bool,
582 pub ewasm: bool,
583 pub assembly: bool,
584 pub legacy_assembly: bool,
585 pub source_map: bool,
586 pub generated_sources: bool,
587 pub bytecode: bool,
588 pub deployed_bytecode: bool,
589
590 #[doc(hidden)]
599 pub __non_exhaustive: (),
600}
601
602impl ExtraOutputFiles {
603 pub fn all() -> Self {
605 Self {
606 abi: true,
607 metadata: true,
608 ir: true,
609 ir_optimized: true,
610 ewasm: true,
611 assembly: true,
612 legacy_assembly: true,
613 source_map: true,
614 generated_sources: true,
615 bytecode: true,
616 deployed_bytecode: true,
617 __non_exhaustive: (),
618 }
619 }
620
621 pub fn from_output_selection(
623 settings: impl IntoIterator<Item = ContractOutputSelection>,
624 ) -> Self {
625 let mut config = Self::default();
626 for value in settings.into_iter() {
627 match value {
628 ContractOutputSelection::Abi => {
629 config.abi = true;
630 }
631 ContractOutputSelection::Metadata => {
632 config.metadata = true;
633 }
634 ContractOutputSelection::Ir => {
635 config.ir = true;
636 }
637 ContractOutputSelection::IrOptimized => {
638 config.ir_optimized = true;
639 }
640 ContractOutputSelection::Evm(evm) => match evm {
641 EvmOutputSelection::All => {
642 config.assembly = true;
643 config.legacy_assembly = true;
644 config.generated_sources = true;
645 config.source_map = true;
646 config.bytecode = true;
647 config.deployed_bytecode = true;
648 }
649 EvmOutputSelection::Assembly => {
650 config.assembly = true;
651 }
652 EvmOutputSelection::LegacyAssembly => {
653 config.legacy_assembly = true;
654 }
655 EvmOutputSelection::ByteCode(BytecodeOutputSelection::GeneratedSources) => {
656 config.generated_sources = true;
657 }
658 EvmOutputSelection::ByteCode(BytecodeOutputSelection::Object) => {
659 config.bytecode = true;
660 }
661 EvmOutputSelection::ByteCode(BytecodeOutputSelection::SourceMap) => {
662 config.source_map = true;
663 }
664 EvmOutputSelection::DeployedByteCode(DeployedBytecodeOutputSelection::All)
665 | EvmOutputSelection::DeployedByteCode(
666 DeployedBytecodeOutputSelection::Object,
667 ) => {
668 config.deployed_bytecode = true;
669 }
670 _ => {}
671 },
672 ContractOutputSelection::Ewasm(_) => {
673 config.ewasm = true;
674 }
675 _ => {}
676 }
677 }
678 config
679 }
680
681 fn process_abi(&self, abi: Option<&JsonAbi>, file: &Path) -> Result<(), SolcError> {
682 if self.abi {
683 if let Some(abi) = abi {
684 let file = file.with_extension("abi.json");
685 fs::write(&file, serde_json::to_string_pretty(abi)?)
686 .map_err(|err| SolcError::io(err, file))?
687 }
688 }
689 Ok(())
690 }
691
692 fn process_metadata(&self, metadata: Option<&Metadata>, file: &Path) -> Result<(), SolcError> {
693 if self.metadata {
694 if let Some(metadata) = metadata {
695 let file = file.with_extension("metadata.json");
696 fs::write(&file, serde_json::to_string_pretty(metadata)?)
697 .map_err(|err| SolcError::io(err, file))?
698 }
699 }
700 Ok(())
701 }
702
703 fn process_ir(&self, ir: Option<&str>, file: &Path) -> Result<(), SolcError> {
704 if self.ir {
705 if let Some(ir) = ir {
706 let file = file.with_extension("ir");
707 fs::write(&file, ir).map_err(|err| SolcError::io(err, file))?
708 }
709 }
710 Ok(())
711 }
712
713 fn process_ir_optimized(
714 &self,
715 ir_optimized: Option<&str>,
716 file: &Path,
717 ) -> Result<(), SolcError> {
718 if self.ir_optimized {
719 if let Some(ir_optimized) = ir_optimized {
720 let file = file.with_extension("iropt");
721 fs::write(&file, ir_optimized).map_err(|err| SolcError::io(err, file))?
722 }
723 }
724 Ok(())
725 }
726
727 fn process_ewasm(&self, ewasm: Option<&Ewasm>, file: &Path) -> Result<(), SolcError> {
728 if self.ewasm {
729 if let Some(ewasm) = ewasm {
730 let file = file.with_extension("ewasm");
731 fs::write(&file, serde_json::to_vec_pretty(ewasm)?)
732 .map_err(|err| SolcError::io(err, file))?;
733 }
734 }
735 Ok(())
736 }
737
738 fn process_assembly(&self, asm: Option<&str>, file: &Path) -> Result<(), SolcError> {
739 if self.assembly {
740 if let Some(asm) = asm {
741 let file = file.with_extension("asm");
742 fs::write(&file, asm).map_err(|err| SolcError::io(err, file))?
743 }
744 }
745 Ok(())
746 }
747
748 fn process_legacy_assembly(
749 &self,
750 asm: Option<serde_json::Value>,
751 file: &Path,
752 ) -> Result<(), SolcError> {
753 if self.legacy_assembly {
754 if let Some(legacy_asm) = asm {
755 let file = file.with_extension("legacyAssembly.json");
756 fs::write(&file, format!("{legacy_asm}")).map_err(|err| SolcError::io(err, file))?
757 }
758 }
759 Ok(())
760 }
761
762 fn process_generated_sources(
763 &self,
764 generated_sources: Option<&Vec<GeneratedSource>>,
765 file: &Path,
766 ) -> Result<(), SolcError> {
767 if self.generated_sources {
768 if let Some(generated_sources) = generated_sources {
769 let file = file.with_extension("gensources");
770 fs::write(&file, serde_json::to_vec_pretty(generated_sources)?)
771 .map_err(|err| SolcError::io(err, file))?;
772 }
773 }
774 Ok(())
775 }
776
777 fn process_source_map(&self, source_map: Option<&str>, file: &Path) -> Result<(), SolcError> {
778 if self.source_map {
779 if let Some(source_map) = source_map {
780 let file = file.with_extension("sourcemap");
781 fs::write(&file, source_map).map_err(|err| SolcError::io(err, file))?
782 }
783 }
784 Ok(())
785 }
786
787 fn process_bytecode(
788 &self,
789 bytecode: Option<&BytecodeObject>,
790 file: &Path,
791 ) -> Result<(), SolcError> {
792 if self.bytecode {
793 if let Some(bytecode) = bytecode {
794 let code = hex::encode(bytecode.as_ref());
795 let file = file.with_extension("bin");
796 fs::write(&file, code).map_err(|err| SolcError::io(err, file))?
797 }
798 }
799 Ok(())
800 }
801
802 fn process_deployed_bytecode(
803 &self,
804 deployed: Option<&BytecodeObject>,
805 file: &Path,
806 ) -> Result<(), SolcError> {
807 if self.deployed_bytecode {
808 if let Some(deployed) = deployed {
809 let code = hex::encode(deployed.as_ref());
810 let file = file.with_extension("deployed-bin");
811 fs::write(&file, code).map_err(|err| SolcError::io(err, file))?
812 }
813 }
814 Ok(())
815 }
816
817 pub fn write_extras(&self, contract: &Contract, file: &Path) -> Result<(), SolcError> {
819 self.process_abi(contract.abi.as_ref(), file)?;
820 self.process_metadata(contract.metadata.as_ref().map(|m| &m.metadata), file)?;
821 self.process_ir(contract.ir.as_deref(), file)?;
822 self.process_ir_optimized(contract.ir_optimized.as_deref(), file)?;
823 self.process_ewasm(contract.ewasm.as_ref(), file)?;
824
825 let evm = contract.evm.as_ref();
826 self.process_assembly(evm.and_then(|evm| evm.assembly.as_deref()), file)?;
827 self.process_legacy_assembly(evm.and_then(|evm| evm.legacy_assembly.clone()), file)?;
828
829 let bytecode = evm.and_then(|evm| evm.bytecode.as_ref());
830 self.process_generated_sources(bytecode.map(|b| &b.generated_sources), file)?;
831
832 let deployed_bytecode = evm.and_then(|evm| evm.deployed_bytecode.as_ref());
833 self.process_source_map(bytecode.and_then(|b| b.source_map.as_deref()), file)?;
834 self.process_bytecode(bytecode.map(|b| &b.object), file)?;
835 self.process_deployed_bytecode(
836 deployed_bytecode.and_then(|d| d.bytecode.as_ref()).map(|b| &b.object),
837 file,
838 )?;
839
840 Ok(())
841 }
842}