feat(solc): include source file ast in artifact (#1081)

* refactor: extend artifactsoutput interface

* add source file to trait

* fix: make it compile again
This commit is contained in:
Matthias Seitz 2022-03-27 18:56:33 +02:00 committed by GitHub
parent 919a570237
commit 2689981782
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 25 deletions

View File

@ -8,7 +8,7 @@ use crate::{
CompactContractBytecodeCow, CompactEvm, DevDoc, Ewasm, GasEstimates, LosslessAbi, Metadata, CompactContractBytecodeCow, CompactEvm, DevDoc, Ewasm, GasEstimates, LosslessAbi, Metadata,
Offsets, Settings, StorageLayout, UserDoc, Offsets, Settings, StorageLayout, UserDoc,
}, },
ArtifactOutput, SolcConfig, SolcError, ArtifactOutput, SolcConfig, SolcError, SourceFile,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{borrow::Cow, collections::BTreeMap, fs, path::Path}; use std::{borrow::Cow, collections::BTreeMap, fs, path::Path};
@ -47,6 +47,8 @@ pub struct ConfigurableContractArtifact {
pub ir_optimized: Option<String>, pub ir_optimized: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
pub ewasm: Option<Ewasm>, pub ewasm: Option<Ewasm>,
#[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
pub ast: serde_json::Value,
} }
impl ConfigurableContractArtifact { impl ConfigurableContractArtifact {
@ -190,7 +192,13 @@ impl ArtifactOutput for ConfigurableArtifacts {
self.additional_files.write_extras(contract, file) self.additional_files.write_extras(contract, file)
} }
fn contract_to_artifact(&self, _file: &str, _name: &str, contract: Contract) -> Self::Artifact { fn contract_to_artifact(
&self,
_file: &str,
_name: &str,
contract: Contract,
source_file: Option<&SourceFile>,
) -> Self::Artifact {
let mut artifact_userdoc = None; let mut artifact_userdoc = None;
let mut artifact_devdoc = None; let mut artifact_devdoc = None;
let mut artifact_metadata = None; let mut artifact_metadata = None;
@ -276,6 +284,7 @@ impl ArtifactOutput for ConfigurableArtifacts {
ir: artifact_ir, ir: artifact_ir,
ir_optimized: artifact_ir_optimized, ir_optimized: artifact_ir_optimized,
ewasm: artifact_ewasm, ewasm: artifact_ewasm,
ast: source_file.map(|s| s.ast.clone()).unwrap_or_default(),
} }
} }
} }

View File

@ -18,6 +18,7 @@ mod configurable;
use crate::artifacts::{ use crate::artifacts::{
contract::{CompactContract, CompactContractBytecode, Contract}, contract::{CompactContract, CompactContractBytecode, Contract},
BytecodeObject, CompactBytecode, CompactContractBytecodeCow, CompactDeployedBytecode, BytecodeObject, CompactBytecode, CompactContractBytecodeCow, CompactDeployedBytecode,
SourceFile,
}; };
pub use configurable::*; pub use configurable::*;
@ -437,9 +438,10 @@ pub trait ArtifactOutput {
fn on_output( fn on_output(
&self, &self,
contracts: &VersionedContracts, contracts: &VersionedContracts,
sources: &BTreeMap<String, SourceFile>,
layout: &ProjectPathsConfig, layout: &ProjectPathsConfig,
) -> Result<Artifacts<Self::Artifact>> { ) -> Result<Artifacts<Self::Artifact>> {
let mut artifacts = self.output_to_artifacts(contracts); let mut artifacts = self.output_to_artifacts(contracts, sources);
artifacts.join_all(&layout.artifacts); artifacts.join_all(&layout.artifacts);
artifacts.write_all()?; artifacts.write_all()?;
@ -581,16 +583,28 @@ pub trait ArtifactOutput {
/// Convert a contract to the artifact type /// Convert a contract to the artifact type
/// ///
/// This is the core conversion function that takes care of converting a `Contract` into the /// This is the core conversion function that takes care of converting a `Contract` into the
/// associated `Artifact` type /// associated `Artifact` type.
fn contract_to_artifact(&self, _file: &str, _name: &str, contract: Contract) -> Self::Artifact; /// The `SourceFile` is also provided
fn contract_to_artifact(
&self,
_file: &str,
_name: &str,
contract: Contract,
source_file: Option<&SourceFile>,
) -> Self::Artifact;
/// Convert the compiler output into a set of artifacts /// Convert the compiler output into a set of artifacts
/// ///
/// **Note:** This does only convert, but _NOT_ write the artifacts to disk, See /// **Note:** This does only convert, but _NOT_ write the artifacts to disk, See
/// [`Self::on_output()`] /// [`Self::on_output()`]
fn output_to_artifacts(&self, contracts: &VersionedContracts) -> Artifacts<Self::Artifact> { fn output_to_artifacts(
&self,
contracts: &VersionedContracts,
sources: &BTreeMap<String, SourceFile>,
) -> Artifacts<Self::Artifact> {
let mut artifacts = ArtifactsMap::new(); let mut artifacts = ArtifactsMap::new();
for (file, contracts) in contracts.as_ref().iter() { for (file, contracts) in contracts.as_ref().iter() {
let source_file = sources.get(file);
let mut entries = BTreeMap::new(); let mut entries = BTreeMap::new();
for (name, versioned_contracts) in contracts { for (name, versioned_contracts) in contracts {
let mut contracts = Vec::with_capacity(versioned_contracts.len()); let mut contracts = Vec::with_capacity(versioned_contracts.len());
@ -601,7 +615,13 @@ pub trait ArtifactOutput {
} else { } else {
Self::output_file(file, name) Self::output_file(file, name)
}; };
let artifact = self.contract_to_artifact(file, name, contract.contract.clone());
let artifact = self.contract_to_artifact(
file,
name,
contract.contract.clone(),
source_file,
);
contracts.push(ArtifactFile { contracts.push(ArtifactFile {
artifact, artifact,
@ -636,7 +656,13 @@ pub struct MinimalCombinedArtifacts {
impl ArtifactOutput for MinimalCombinedArtifacts { impl ArtifactOutput for MinimalCombinedArtifacts {
type Artifact = CompactContractBytecode; type Artifact = CompactContractBytecode;
fn contract_to_artifact(&self, _file: &str, _name: &str, contract: Contract) -> Self::Artifact { fn contract_to_artifact(
&self,
_file: &str,
_name: &str,
contract: Contract,
_source_file: Option<&SourceFile>,
) -> Self::Artifact {
Self::Artifact::from(contract) Self::Artifact::from(contract)
} }
} }
@ -654,9 +680,10 @@ impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback {
fn on_output( fn on_output(
&self, &self,
output: &VersionedContracts, output: &VersionedContracts,
sources: &BTreeMap<String, SourceFile>,
layout: &ProjectPathsConfig, layout: &ProjectPathsConfig,
) -> Result<Artifacts<Self::Artifact>> { ) -> Result<Artifacts<Self::Artifact>> {
MinimalCombinedArtifacts::default().on_output(output, layout) MinimalCombinedArtifacts::default().on_output(output, sources, layout)
} }
fn read_cached_artifact(path: impl AsRef<Path>) -> Result<Self::Artifact> { fn read_cached_artifact(path: impl AsRef<Path>) -> Result<Self::Artifact> {
@ -673,8 +700,14 @@ impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback {
} }
} }
fn contract_to_artifact(&self, file: &str, name: &str, contract: Contract) -> Self::Artifact { fn contract_to_artifact(
MinimalCombinedArtifacts::default().contract_to_artifact(file, name, contract) &self,
file: &str,
name: &str,
contract: Contract,
source_file: Option<&SourceFile>,
) -> Self::Artifact {
MinimalCombinedArtifacts::default().contract_to_artifact(file, name, contract, source_file)
} }
} }

View File

@ -266,15 +266,22 @@ impl<'a, T: ArtifactOutput> CompiledState<'a, T> {
// write all artifacts via the handler but only if the build succeeded // write all artifacts via the handler but only if the build succeeded
let compiled_artifacts = if cache.project().no_artifacts { let compiled_artifacts = if cache.project().no_artifacts {
cache.project().artifacts_handler().output_to_artifacts(&output.contracts)
} else if output.has_error() {
tracing::trace!("skip writing cache file due to solc errors: {:?}", output.errors);
cache.project().artifacts_handler().output_to_artifacts(&output.contracts)
} else {
cache cache
.project() .project()
.artifacts_handler() .artifacts_handler()
.on_output(&output.contracts, &cache.project().paths)? .output_to_artifacts(&output.contracts, &output.sources)
} else if output.has_error() {
tracing::trace!("skip writing cache file due to solc errors: {:?}", output.errors);
cache
.project()
.artifacts_handler()
.output_to_artifacts(&output.contracts, &output.sources)
} else {
cache.project().artifacts_handler().on_output(
&output.contracts,
&output.sources,
&cache.project().paths,
)?
}; };
Ok(ArtifactsState { output, cache, compiled_artifacts }) Ok(ArtifactsState { output, cache, compiled_artifacts })

View File

@ -6,7 +6,7 @@ use crate::{
contract::{CompactContract, CompactContractBytecode, Contract, ContractBytecode}, contract::{CompactContract, CompactContractBytecode, Contract, ContractBytecode},
CompactContractBytecodeCow, LosslessAbi, Offsets, CompactContractBytecodeCow, LosslessAbi, Offsets,
}, },
ArtifactOutput, ArtifactOutput, SourceFile,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{borrow::Cow, collections::btree_map::BTreeMap}; use std::{borrow::Cow, collections::btree_map::BTreeMap};
@ -97,7 +97,13 @@ pub struct HardhatArtifacts {
impl ArtifactOutput for HardhatArtifacts { impl ArtifactOutput for HardhatArtifacts {
type Artifact = HardhatArtifact; type Artifact = HardhatArtifact;
fn contract_to_artifact(&self, file: &str, name: &str, contract: Contract) -> Self::Artifact { fn contract_to_artifact(
&self,
file: &str,
name: &str,
contract: Contract,
_source_file: Option<&SourceFile>,
) -> Self::Artifact {
let (bytecode, link_references, deployed_bytecode, deployed_link_references) = let (bytecode, link_references, deployed_bytecode, deployed_link_references) =
if let Some(evm) = contract.evm { if let Some(evm) = contract.evm {
let (deployed_bytecode, deployed_link_references) = let (deployed_bytecode, deployed_link_references) =

View File

@ -24,7 +24,7 @@ mod config;
pub use config::{AllowedLibPaths, PathStyle, ProjectPathsConfig, SolcConfig}; pub use config::{AllowedLibPaths, PathStyle, ProjectPathsConfig, SolcConfig};
pub mod remappings; pub mod remappings;
use crate::artifacts::Source; use crate::artifacts::{Source, SourceFile};
pub mod error; pub mod error;
mod filter; mod filter;
@ -677,9 +677,10 @@ impl<T: ArtifactOutput> ArtifactOutput for Project<T> {
fn on_output( fn on_output(
&self, &self,
contracts: &VersionedContracts, contracts: &VersionedContracts,
sources: &BTreeMap<String, SourceFile>,
layout: &ProjectPathsConfig, layout: &ProjectPathsConfig,
) -> Result<Artifacts<Self::Artifact>> { ) -> Result<Artifacts<Self::Artifact>> {
self.artifacts_handler().on_output(contracts, layout) self.artifacts_handler().on_output(contracts, sources, layout)
} }
fn write_contract_extras(&self, contract: &Contract, file: &Path) -> Result<()> { fn write_contract_extras(&self, contract: &Contract, file: &Path) -> Result<()> {
@ -738,12 +739,22 @@ impl<T: ArtifactOutput> ArtifactOutput for Project<T> {
T::read_cached_artifacts(files) T::read_cached_artifacts(files)
} }
fn contract_to_artifact(&self, file: &str, name: &str, contract: Contract) -> Self::Artifact { fn contract_to_artifact(
self.artifacts_handler().contract_to_artifact(file, name, contract) &self,
file: &str,
name: &str,
contract: Contract,
source_file: Option<&SourceFile>,
) -> Self::Artifact {
self.artifacts_handler().contract_to_artifact(file, name, contract, source_file)
} }
fn output_to_artifacts(&self, contracts: &VersionedContracts) -> Artifacts<Self::Artifact> { fn output_to_artifacts(
self.artifacts_handler().output_to_artifacts(contracts) &self,
contracts: &VersionedContracts,
sources: &BTreeMap<String, SourceFile>,
) -> Artifacts<Self::Artifact> {
self.artifacts_handler().output_to_artifacts(contracts, sources)
} }
} }