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_with_profile(
184 file,
185 name,
186 &contract.version,
187 &contract.profile,
188 ) {
189 let file = &artifact.file;
190 utils::create_parent_dir_all(file)?;
191 self.additional_files.write_extras(&contract.contract, file)?;
192 }
193 }
194 }
195 }
196 Ok(())
197 }
198
199 fn contract_to_artifact(
200 &self,
201 _file: &Path,
202 _name: &str,
203 contract: Contract,
204 source_file: Option<&SourceFile>,
205 ) -> Self::Artifact {
206 let mut artifact_userdoc = None;
207 let mut artifact_devdoc = None;
208 let mut artifact_raw_metadata = None;
209 let mut artifact_metadata = None;
210 let mut artifact_ir = None;
211 let mut artifact_ir_optimized = None;
212 let mut artifact_ir_optimized_ast = None;
213 let mut artifact_ewasm = None;
214 let mut artifact_bytecode = None;
215 let mut artifact_deployed_bytecode = None;
216 let mut artifact_gas_estimates = None;
217 let mut artifact_function_debug_data = None;
218 let mut artifact_method_identifiers = None;
219 let mut artifact_assembly = None;
220 let mut artifact_legacy_assembly = None;
221 let mut artifact_storage_layout = None;
222 let mut artifact_transient_storage_layout = None;
223 let mut generated_sources = None;
224 let mut opcodes = None;
225
226 let Contract {
227 abi,
228 metadata,
229 userdoc,
230 devdoc,
231 ir,
232 storage_layout,
233 transient_storage_layout,
234 evm,
235 ewasm,
236 ir_optimized,
237 ir_optimized_ast,
238 } = contract;
239
240 if self.additional_values.metadata || self.additional_files.metadata {
241 if let Some(LosslessMetadata { raw_metadata, metadata }) = metadata {
242 artifact_raw_metadata = Some(raw_metadata);
243 artifact_metadata = Some(metadata);
244 }
245 }
246 if self.additional_values.userdoc {
247 artifact_userdoc = Some(userdoc);
248 }
249 if self.additional_values.devdoc {
250 artifact_devdoc = Some(devdoc);
251 }
252 if self.additional_values.ewasm || self.additional_files.ewasm {
253 artifact_ewasm = ewasm;
254 }
255 if self.additional_values.ir || self.additional_files.ir {
256 artifact_ir = ir;
257 }
258 if self.additional_values.ir_optimized || self.additional_files.ir_optimized {
259 artifact_ir_optimized = ir_optimized;
260 }
261 if self.additional_values.ir_optimized_ast {
262 artifact_ir_optimized_ast = ir_optimized_ast;
263 }
264 if self.additional_values.storage_layout {
265 artifact_storage_layout = Some(storage_layout);
266 }
267 if self.additional_values.transient_storage_layout {
268 artifact_transient_storage_layout = Some(transient_storage_layout);
269 }
270
271 if let Some(evm) = evm {
272 let Evm {
273 assembly,
274 mut bytecode,
275 deployed_bytecode,
276 method_identifiers,
277 gas_estimates,
278 legacy_assembly,
279 } = evm;
280
281 if self.additional_values.function_debug_data {
282 artifact_function_debug_data =
283 bytecode.as_mut().map(|code| std::mem::take(&mut code.function_debug_data));
284 }
285 if self.additional_values.generated_sources {
286 generated_sources =
287 bytecode.as_mut().map(|code| std::mem::take(&mut code.generated_sources));
288 }
289
290 if self.additional_values.opcodes {
291 opcodes = bytecode.as_mut().and_then(|code| code.opcodes.take())
292 }
293
294 artifact_bytecode = bytecode.map(Into::into);
295 artifact_deployed_bytecode = deployed_bytecode.map(Into::into);
296 artifact_method_identifiers = Some(method_identifiers);
297
298 if self.additional_values.gas_estimates {
299 artifact_gas_estimates = gas_estimates;
300 }
301 if self.additional_values.assembly || self.additional_files.assembly {
302 artifact_assembly = assembly;
303 }
304
305 if self.additional_values.legacy_assembly || self.additional_files.legacy_assembly {
306 artifact_legacy_assembly = legacy_assembly;
307 }
308 }
309
310 ConfigurableContractArtifact {
311 abi,
312 bytecode: artifact_bytecode,
313 deployed_bytecode: artifact_deployed_bytecode,
314 assembly: artifact_assembly,
315 legacy_assembly: artifact_legacy_assembly,
316 opcodes,
317 function_debug_data: artifact_function_debug_data,
318 method_identifiers: artifact_method_identifiers,
319 gas_estimates: artifact_gas_estimates,
320 raw_metadata: artifact_raw_metadata,
321 metadata: artifact_metadata,
322 storage_layout: artifact_storage_layout,
323 transient_storage_layout: artifact_transient_storage_layout,
324 userdoc: artifact_userdoc,
325 devdoc: artifact_devdoc,
326 ir: artifact_ir,
327 ir_optimized: artifact_ir_optimized,
328 ir_optimized_ast: artifact_ir_optimized_ast,
329 ewasm: artifact_ewasm,
330 id: source_file.as_ref().map(|s| s.id),
331 ast: source_file.and_then(|s| s.ast.clone()),
332 generated_sources: generated_sources.unwrap_or_default(),
333 }
334 }
335
336 fn standalone_source_file_to_artifact(
337 &self,
338 _path: &Path,
339 file: &VersionedSourceFile,
340 ) -> Option<Self::Artifact> {
341 file.source_file.ast.clone().map(|ast| ConfigurableContractArtifact {
342 abi: Some(JsonAbi::default()),
343 id: Some(file.source_file.id),
344 ast: Some(ast),
345 bytecode: Some(CompactBytecode::empty()),
346 deployed_bytecode: Some(CompactDeployedBytecode::empty()),
347 ..Default::default()
348 })
349 }
350
351 fn is_dirty(&self, artifact_file: &ArtifactFile<Self::Artifact>) -> Result<bool, SolcError> {
354 let artifact = &artifact_file.artifact;
355 let ExtraOutputFiles {
356 abi: _,
357 metadata,
358 ir,
359 ir_optimized,
360 ewasm,
361 assembly,
362 legacy_assembly,
363 source_map,
364 generated_sources,
365 bytecode: _,
366 deployed_bytecode: _,
367 __non_exhaustive: _,
368 } = self.additional_files;
369
370 if metadata && artifact.metadata.is_none() {
371 return Ok(true);
372 }
373 if ir && artifact.ir.is_none() {
374 return Ok(true);
375 }
376 if ir_optimized && artifact.ir_optimized.is_none() {
377 return Ok(true);
378 }
379 if ewasm && artifact.ewasm.is_none() {
380 return Ok(true);
381 }
382 if assembly && artifact.assembly.is_none() {
383 return Ok(true);
384 }
385 if legacy_assembly && artifact.legacy_assembly.is_none() {
386 return Ok(true);
387 }
388 if source_map && artifact.get_source_map_str().is_none() {
389 return Ok(true);
390 }
391 if generated_sources {
392 return Ok(true);
394 }
395 Ok(false)
396 }
397
398 fn handle_cached_artifacts(
400 &self,
401 artifacts: &crate::Artifacts<Self::Artifact>,
402 ) -> Result<(), SolcError> {
403 for artifacts in artifacts.values() {
404 for artifacts in artifacts.values() {
405 for artifact_file in artifacts {
406 let file = &artifact_file.file;
407 let artifact = &artifact_file.artifact;
408 self.additional_files.process_abi(artifact.abi.as_ref(), file)?;
409 self.additional_files.process_assembly(artifact.assembly.as_deref(), file)?;
410 self.additional_files
411 .process_legacy_assembly(artifact.legacy_assembly.clone(), file)?;
412 self.additional_files
413 .process_bytecode(artifact.bytecode.as_ref().map(|b| &b.object), file)?;
414 self.additional_files.process_deployed_bytecode(
415 artifact
416 .deployed_bytecode
417 .as_ref()
418 .and_then(|d| d.bytecode.as_ref())
419 .map(|b| &b.object),
420 file,
421 )?;
422 self.additional_files
423 .process_generated_sources(Some(&artifact.generated_sources), file)?;
424 self.additional_files.process_ir(artifact.ir.as_deref(), file)?;
425 self.additional_files
426 .process_ir_optimized(artifact.ir_optimized.as_deref(), file)?;
427 self.additional_files.process_ewasm(artifact.ewasm.as_ref(), file)?;
428 self.additional_files.process_metadata(artifact.metadata.as_ref(), file)?;
429 self.additional_files
430 .process_source_map(artifact.get_source_map_str().as_deref(), file)?;
431 }
432 }
433 }
434
435 Ok(())
436 }
437}
438
439#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
441pub struct ExtraOutputValues {
442 pub ast: bool,
443 pub userdoc: bool,
444 pub devdoc: bool,
445 pub method_identifiers: bool,
446 pub storage_layout: bool,
447 pub transient_storage_layout: bool,
448 pub assembly: bool,
449 pub legacy_assembly: bool,
450 pub gas_estimates: bool,
451 pub metadata: bool,
452 pub ir: bool,
453 pub ir_optimized: bool,
454 pub ir_optimized_ast: bool,
455 pub ewasm: bool,
456 pub function_debug_data: bool,
457 pub generated_sources: bool,
458 pub source_map: bool,
459 pub opcodes: bool,
460
461 #[doc(hidden)]
470 pub __non_exhaustive: (),
471}
472
473impl ExtraOutputValues {
474 pub fn all() -> Self {
476 Self {
477 ast: true,
478 userdoc: true,
479 devdoc: true,
480 method_identifiers: true,
481 storage_layout: true,
482 transient_storage_layout: true,
483 assembly: true,
484 legacy_assembly: true,
485 gas_estimates: true,
486 metadata: true,
487 ir: true,
488 ir_optimized: true,
489 ir_optimized_ast: true,
490 ewasm: true,
491 function_debug_data: true,
492 generated_sources: true,
493 source_map: true,
494 opcodes: true,
495 __non_exhaustive: (),
496 }
497 }
498
499 pub fn from_output_selection(
501 settings: impl IntoIterator<Item = ContractOutputSelection>,
502 ) -> Self {
503 let mut config = Self::default();
504 for value in settings.into_iter() {
505 match value {
506 ContractOutputSelection::DevDoc => {
507 config.devdoc = true;
508 }
509 ContractOutputSelection::UserDoc => {
510 config.userdoc = true;
511 }
512 ContractOutputSelection::Metadata => {
513 config.metadata = true;
514 }
515 ContractOutputSelection::Ir => {
516 config.ir = true;
517 }
518 ContractOutputSelection::IrOptimized => {
519 config.ir_optimized = true;
520 }
521 ContractOutputSelection::StorageLayout => {
522 config.storage_layout = true;
523 }
524 ContractOutputSelection::Evm(evm) => match evm {
525 EvmOutputSelection::All => {
526 config.assembly = true;
527 config.legacy_assembly = true;
528 config.gas_estimates = true;
529 config.method_identifiers = true;
530 config.generated_sources = true;
531 config.source_map = true;
532 config.opcodes = true;
533 }
534 EvmOutputSelection::Assembly => {
535 config.assembly = true;
536 }
537 EvmOutputSelection::LegacyAssembly => {
538 config.legacy_assembly = true;
539 }
540 EvmOutputSelection::MethodIdentifiers => {
541 config.method_identifiers = true;
542 }
543 EvmOutputSelection::GasEstimates => {
544 config.gas_estimates = true;
545 }
546 EvmOutputSelection::ByteCode(BytecodeOutputSelection::FunctionDebugData) => {
547 config.function_debug_data = true;
548 }
549 EvmOutputSelection::ByteCode(BytecodeOutputSelection::Opcodes) => {
550 config.opcodes = true;
551 }
552 EvmOutputSelection::ByteCode(BytecodeOutputSelection::GeneratedSources) => {
553 config.generated_sources = true;
554 }
555 EvmOutputSelection::ByteCode(BytecodeOutputSelection::SourceMap) => {
556 config.source_map = true;
557 }
558 _ => {}
559 },
560 ContractOutputSelection::Ewasm(_) => {
561 config.ewasm = true;
562 }
563 ContractOutputSelection::IrOptimizedAst => {
564 config.ir_optimized_ast = true;
565 }
566 ContractOutputSelection::TransientStorageLayout => {
567 config.transient_storage_layout = true;
568 }
569 ContractOutputSelection::Abi => {}
570 }
571 }
572
573 config
574 }
575}
576
577#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
579pub struct ExtraOutputFiles {
580 pub abi: bool,
581 pub metadata: bool,
582 pub ir: bool,
583 pub ir_optimized: bool,
584 pub ewasm: bool,
585 pub assembly: bool,
586 pub legacy_assembly: bool,
587 pub source_map: bool,
588 pub generated_sources: bool,
589 pub bytecode: bool,
590 pub deployed_bytecode: bool,
591
592 #[doc(hidden)]
601 pub __non_exhaustive: (),
602}
603
604impl ExtraOutputFiles {
605 pub fn all() -> Self {
607 Self {
608 abi: true,
609 metadata: true,
610 ir: true,
611 ir_optimized: true,
612 ewasm: true,
613 assembly: true,
614 legacy_assembly: true,
615 source_map: true,
616 generated_sources: true,
617 bytecode: true,
618 deployed_bytecode: true,
619 __non_exhaustive: (),
620 }
621 }
622
623 pub fn from_output_selection(
625 settings: impl IntoIterator<Item = ContractOutputSelection>,
626 ) -> Self {
627 let mut config = Self::default();
628 for value in settings.into_iter() {
629 match value {
630 ContractOutputSelection::Abi => {
631 config.abi = true;
632 }
633 ContractOutputSelection::Metadata => {
634 config.metadata = true;
635 }
636 ContractOutputSelection::Ir => {
637 config.ir = true;
638 }
639 ContractOutputSelection::IrOptimized => {
640 config.ir_optimized = true;
641 }
642 ContractOutputSelection::Evm(evm) => match evm {
643 EvmOutputSelection::All => {
644 config.assembly = true;
645 config.legacy_assembly = true;
646 config.generated_sources = true;
647 config.source_map = true;
648 config.bytecode = true;
649 config.deployed_bytecode = true;
650 }
651 EvmOutputSelection::Assembly => {
652 config.assembly = true;
653 }
654 EvmOutputSelection::LegacyAssembly => {
655 config.legacy_assembly = true;
656 }
657 EvmOutputSelection::ByteCode(BytecodeOutputSelection::GeneratedSources) => {
658 config.generated_sources = true;
659 }
660 EvmOutputSelection::ByteCode(BytecodeOutputSelection::Object) => {
661 config.bytecode = true;
662 }
663 EvmOutputSelection::ByteCode(BytecodeOutputSelection::SourceMap) => {
664 config.source_map = true;
665 }
666 EvmOutputSelection::DeployedByteCode(DeployedBytecodeOutputSelection::All)
667 | EvmOutputSelection::DeployedByteCode(
668 DeployedBytecodeOutputSelection::Object,
669 ) => {
670 config.deployed_bytecode = true;
671 }
672 _ => {}
673 },
674 ContractOutputSelection::Ewasm(_) => {
675 config.ewasm = true;
676 }
677 _ => {}
678 }
679 }
680 config
681 }
682
683 fn process_abi(&self, abi: Option<&JsonAbi>, file: &Path) -> Result<(), SolcError> {
684 if self.abi {
685 if let Some(abi) = abi {
686 let file = file.with_extension("abi.json");
687 fs::write(&file, serde_json::to_string_pretty(abi)?)
688 .map_err(|err| SolcError::io(err, file))?
689 }
690 }
691 Ok(())
692 }
693
694 fn process_metadata(&self, metadata: Option<&Metadata>, file: &Path) -> Result<(), SolcError> {
695 if self.metadata {
696 if let Some(metadata) = metadata {
697 let file = file.with_extension("metadata.json");
698 fs::write(&file, serde_json::to_string_pretty(metadata)?)
699 .map_err(|err| SolcError::io(err, file))?
700 }
701 }
702 Ok(())
703 }
704
705 fn process_ir(&self, ir: Option<&str>, file: &Path) -> Result<(), SolcError> {
706 if self.ir {
707 if let Some(ir) = ir {
708 let file = file.with_extension("ir");
709 fs::write(&file, ir).map_err(|err| SolcError::io(err, file))?
710 }
711 }
712 Ok(())
713 }
714
715 fn process_ir_optimized(
716 &self,
717 ir_optimized: Option<&str>,
718 file: &Path,
719 ) -> Result<(), SolcError> {
720 if self.ir_optimized {
721 if let Some(ir_optimized) = ir_optimized {
722 let file = file.with_extension("iropt");
723 fs::write(&file, ir_optimized).map_err(|err| SolcError::io(err, file))?
724 }
725 }
726 Ok(())
727 }
728
729 fn process_ewasm(&self, ewasm: Option<&Ewasm>, file: &Path) -> Result<(), SolcError> {
730 if self.ewasm {
731 if let Some(ewasm) = ewasm {
732 let file = file.with_extension("ewasm");
733 fs::write(&file, serde_json::to_vec_pretty(ewasm)?)
734 .map_err(|err| SolcError::io(err, file))?;
735 }
736 }
737 Ok(())
738 }
739
740 fn process_assembly(&self, asm: Option<&str>, file: &Path) -> Result<(), SolcError> {
741 if self.assembly {
742 if let Some(asm) = asm {
743 let file = file.with_extension("asm");
744 fs::write(&file, asm).map_err(|err| SolcError::io(err, file))?
745 }
746 }
747 Ok(())
748 }
749
750 fn process_legacy_assembly(
751 &self,
752 asm: Option<serde_json::Value>,
753 file: &Path,
754 ) -> Result<(), SolcError> {
755 if self.legacy_assembly {
756 if let Some(legacy_asm) = asm {
757 let file = file.with_extension("legacyAssembly.json");
758 fs::write(&file, format!("{legacy_asm}")).map_err(|err| SolcError::io(err, file))?
759 }
760 }
761 Ok(())
762 }
763
764 fn process_generated_sources(
765 &self,
766 generated_sources: Option<&Vec<GeneratedSource>>,
767 file: &Path,
768 ) -> Result<(), SolcError> {
769 if self.generated_sources {
770 if let Some(generated_sources) = generated_sources {
771 let file = file.with_extension("gensources");
772 fs::write(&file, serde_json::to_vec_pretty(generated_sources)?)
773 .map_err(|err| SolcError::io(err, file))?;
774 }
775 }
776 Ok(())
777 }
778
779 fn process_source_map(&self, source_map: Option<&str>, file: &Path) -> Result<(), SolcError> {
780 if self.source_map {
781 if let Some(source_map) = source_map {
782 let file = file.with_extension("sourcemap");
783 fs::write(&file, source_map).map_err(|err| SolcError::io(err, file))?
784 }
785 }
786 Ok(())
787 }
788
789 fn process_bytecode(
790 &self,
791 bytecode: Option<&BytecodeObject>,
792 file: &Path,
793 ) -> Result<(), SolcError> {
794 if self.bytecode {
795 if let Some(bytecode) = bytecode {
796 let code = hex::encode(bytecode.as_ref());
797 let file = file.with_extension("bin");
798 fs::write(&file, code).map_err(|err| SolcError::io(err, file))?
799 }
800 }
801 Ok(())
802 }
803
804 fn process_deployed_bytecode(
805 &self,
806 deployed: Option<&BytecodeObject>,
807 file: &Path,
808 ) -> Result<(), SolcError> {
809 if self.deployed_bytecode {
810 if let Some(deployed) = deployed {
811 let code = hex::encode(deployed.as_ref());
812 let file = file.with_extension("deployed-bin");
813 fs::write(&file, code).map_err(|err| SolcError::io(err, file))?
814 }
815 }
816 Ok(())
817 }
818
819 pub fn write_extras(&self, contract: &Contract, file: &Path) -> Result<(), SolcError> {
821 self.process_abi(contract.abi.as_ref(), file)?;
822 self.process_metadata(contract.metadata.as_ref().map(|m| &m.metadata), file)?;
823 self.process_ir(contract.ir.as_deref(), file)?;
824 self.process_ir_optimized(contract.ir_optimized.as_deref(), file)?;
825 self.process_ewasm(contract.ewasm.as_ref(), file)?;
826
827 let evm = contract.evm.as_ref();
828 self.process_assembly(evm.and_then(|evm| evm.assembly.as_deref()), file)?;
829 self.process_legacy_assembly(evm.and_then(|evm| evm.legacy_assembly.clone()), file)?;
830
831 let bytecode = evm.and_then(|evm| evm.bytecode.as_ref());
832 self.process_generated_sources(bytecode.map(|b| &b.generated_sources), file)?;
833
834 let deployed_bytecode = evm.and_then(|evm| evm.deployed_bytecode.as_ref());
835 self.process_source_map(bytecode.and_then(|b| b.source_map.as_deref()), file)?;
836 self.process_bytecode(bytecode.map(|b| &b.object), file)?;
837 self.process_deployed_bytecode(
838 deployed_bytecode.and_then(|d| d.bytecode.as_ref()).map(|b| &b.object),
839 file,
840 )?;
841
842 Ok(())
843 }
844}