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,
Offsets, Settings, StorageLayout, UserDoc,
},
ArtifactOutput, SolcConfig, SolcError,
ArtifactOutput, SolcConfig, SolcError, SourceFile,
};
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, collections::BTreeMap, fs, path::Path};
@ -47,6 +47,8 @@ pub struct ConfigurableContractArtifact {
pub ir_optimized: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ewasm: Option<Ewasm>,
#[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
pub ast: serde_json::Value,
}
impl ConfigurableContractArtifact {
@ -190,7 +192,13 @@ impl ArtifactOutput for ConfigurableArtifacts {
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_devdoc = None;
let mut artifact_metadata = None;
@ -276,6 +284,7 @@ impl ArtifactOutput for ConfigurableArtifacts {
ir: artifact_ir,
ir_optimized: artifact_ir_optimized,
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::{
contract::{CompactContract, CompactContractBytecode, Contract},
BytecodeObject, CompactBytecode, CompactContractBytecodeCow, CompactDeployedBytecode,
SourceFile,
};
pub use configurable::*;
@ -437,9 +438,10 @@ pub trait ArtifactOutput {
fn on_output(
&self,
contracts: &VersionedContracts,
sources: &BTreeMap<String, SourceFile>,
layout: &ProjectPathsConfig,
) -> 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.write_all()?;
@ -581,16 +583,28 @@ pub trait ArtifactOutput {
/// Convert a contract to the artifact type
///
/// This is the core conversion function that takes care of converting a `Contract` into the
/// associated `Artifact` type
fn contract_to_artifact(&self, _file: &str, _name: &str, contract: Contract) -> Self::Artifact;
/// associated `Artifact` type.
/// 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
///
/// **Note:** This does only convert, but _NOT_ write the artifacts to disk, See
/// [`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();
for (file, contracts) in contracts.as_ref().iter() {
let source_file = sources.get(file);
let mut entries = BTreeMap::new();
for (name, versioned_contracts) in contracts {
let mut contracts = Vec::with_capacity(versioned_contracts.len());
@ -601,7 +615,13 @@ pub trait ArtifactOutput {
} else {
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 {
artifact,
@ -636,7 +656,13 @@ pub struct MinimalCombinedArtifacts {
impl ArtifactOutput for MinimalCombinedArtifacts {
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)
}
}
@ -654,9 +680,10 @@ impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback {
fn on_output(
&self,
output: &VersionedContracts,
sources: &BTreeMap<String, SourceFile>,
layout: &ProjectPathsConfig,
) -> 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> {
@ -673,8 +700,14 @@ impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback {
}
}
fn contract_to_artifact(&self, file: &str, name: &str, contract: Contract) -> Self::Artifact {
MinimalCombinedArtifacts::default().contract_to_artifact(file, name, contract)
fn contract_to_artifact(
&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
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
.project()
.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 })

View File

@ -6,7 +6,7 @@ use crate::{
contract::{CompactContract, CompactContractBytecode, Contract, ContractBytecode},
CompactContractBytecodeCow, LosslessAbi, Offsets,
},
ArtifactOutput,
ArtifactOutput, SourceFile,
};
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, collections::btree_map::BTreeMap};
@ -97,7 +97,13 @@ pub struct HardhatArtifacts {
impl ArtifactOutput for HardhatArtifacts {
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) =
if let Some(evm) = contract.evm {
let (deployed_bytecode, deployed_link_references) =

View File

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