From c9a8c2db6cd734b4c055be7b7a2e7e60f5a7dc12 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Wed, 12 Jun 2024 23:54:23 +0300 Subject: [PATCH 01/22] [wip] refactor: extract artifacts to separate crate --- Cargo.toml | 120 ++------- crates/artifacts/Cargo.toml | 35 +++ .../artifacts/src}/ast/lowfidelity.rs | 2 +- .../artifacts/src}/ast/macros.rs | 0 .../artifacts/src}/ast/misc.rs | 0 .../artifacts/src}/ast/mod.rs | 2 +- .../artifacts/src}/ast/util.rs | 0 .../artifacts/src}/ast/visitor.rs | 0 .../artifacts/src}/ast/yul.rs | 2 +- .../artifacts/src}/bytecode.rs | 5 +- .../artifacts/src}/contract.rs | 2 +- .../artifacts/src}/error.rs | 0 {src => crates/artifacts/src}/hh.rs | 85 +------ .../mod.rs => crates/artifacts/src/lib.rs | 239 ++++++------------ .../artifacts/src}/output_selection.rs | 0 {src => crates/artifacts/src}/remappings.rs | 2 +- .../artifacts/src}/serde_helpers.rs | 0 {src => crates/artifacts/src}/sourcemap.rs | 0 crates/artifacts/src/sources.rs | 162 ++++++++++++ .../artifacts/src}/vyper/error.rs | 30 +-- .../artifacts/src}/vyper/input.rs | 59 +---- crates/artifacts/src/vyper/mod.rs | 11 + .../artifacts/src}/vyper/output.rs | 24 +- .../artifacts/src}/vyper/settings.rs | 23 +- crates/core/Cargo.toml | 34 +++ {src => crates/core/src}/error.rs | 4 +- crates/core/src/lib.rs | 2 + {src => crates/core/src}/utils.rs | 78 +++++- crates/project/Cargo.toml | 43 ++++ crates/project/LICENSE-APACHE | 176 +++++++++++++ crates/project/LICENSE-MIT | 19 ++ crates/project/README.md | 0 .../src}/artifact_output/configurable.rs | 29 ++- crates/project/src/artifact_output/hh.rs | 79 ++++++ .../project/src}/artifact_output/mod.rs | 37 ++- {src => crates/project/src}/buildinfo.rs | 7 +- {src => crates/project/src}/cache.rs | 16 +- {src => crates/project/src}/compile/many.rs | 5 +- crates/project/src/compile/mod.rs | 6 + .../project/src}/compile/output/contracts.rs | 9 +- .../project/src}/compile/output/info.rs | 0 .../project/src}/compile/output/mod.rs | 66 +---- .../project/src}/compile/output/sources.rs | 0 .../project/src}/compile/project.rs | 14 +- {src => crates/project/src}/compilers/mod.rs | 20 +- .../project/src}/compilers/multi.rs | 25 +- .../project/src/compilers/solc/compiler.rs | 60 +---- .../project/src/compilers/solc/mod.rs | 44 +--- crates/project/src/compilers/vyper/error.rs | 26 ++ crates/project/src/compilers/vyper/input.rs | 55 ++++ .../project/src}/compilers/vyper/mod.rs | 17 +- crates/project/src/compilers/vyper/output.rs | 15 ++ .../project/src}/compilers/vyper/parser.rs | 10 +- .../project/src/compilers/vyper/settings.rs | 16 ++ {src => crates/project/src}/config.rs | 17 +- {src => crates/project/src}/filter.rs | 2 +- {src => crates/project/src}/flatten.rs | 21 +- {src => crates/project/src}/lib.rs | 35 +-- .../project/src}/project_util/mock.rs | 0 .../project/src}/project_util/mod.rs | 0 .../project/src}/report/compiler.rs | 2 +- {src => crates/project/src}/report/mod.rs | 2 +- {src => crates/project/src}/resolver/mod.rs | 11 +- {src => crates/project/src}/resolver/parse.rs | 43 ++-- {src => crates/project/src}/resolver/tree.rs | 0 65 files changed, 1060 insertions(+), 788 deletions(-) create mode 100644 crates/artifacts/Cargo.toml rename {src/artifacts => crates/artifacts/src}/ast/lowfidelity.rs (99%) rename {src/artifacts => crates/artifacts/src}/ast/macros.rs (100%) rename {src/artifacts => crates/artifacts/src}/ast/misc.rs (100%) rename {src/artifacts => crates/artifacts/src}/ast/mod.rs (99%) rename {src/artifacts => crates/artifacts/src}/ast/util.rs (100%) rename {src/artifacts => crates/artifacts/src}/ast/visitor.rs (100%) rename {src/artifacts => crates/artifacts/src}/ast/yul.rs (99%) rename {src/artifacts => crates/artifacts/src}/bytecode.rs (99%) rename {src/artifacts => crates/artifacts/src}/contract.rs (99%) rename {src/artifacts => crates/artifacts/src}/error.rs (100%) rename {src => crates/artifacts/src}/hh.rs (52%) rename src/artifacts/mod.rs => crates/artifacts/src/lib.rs (93%) rename {src/artifacts => crates/artifacts/src}/output_selection.rs (100%) rename {src => crates/artifacts/src}/remappings.rs (99%) rename {src/artifacts => crates/artifacts/src}/serde_helpers.rs (100%) rename {src => crates/artifacts/src}/sourcemap.rs (100%) create mode 100644 crates/artifacts/src/sources.rs rename {src/compilers => crates/artifacts/src}/vyper/error.rs (71%) rename {src/compilers => crates/artifacts/src}/vyper/input.rs (54%) create mode 100644 crates/artifacts/src/vyper/mod.rs rename {src/compilers => crates/artifacts/src}/vyper/output.rs (87%) rename {src/compilers => crates/artifacts/src}/vyper/settings.rs (75%) create mode 100644 crates/core/Cargo.toml rename {src => crates/core/src}/error.rs (96%) create mode 100644 crates/core/src/lib.rs rename {src => crates/core/src}/utils.rs (90%) create mode 100644 crates/project/Cargo.toml create mode 100644 crates/project/LICENSE-APACHE create mode 100644 crates/project/LICENSE-MIT create mode 100644 crates/project/README.md rename {src => crates/project/src}/artifact_output/configurable.rs (97%) create mode 100644 crates/project/src/artifact_output/hh.rs rename {src => crates/project/src}/artifact_output/mod.rs (98%) rename {src => crates/project/src}/buildinfo.rs (97%) rename {src => crates/project/src}/cache.rs (99%) rename {src => crates/project/src}/compile/many.rs (88%) create mode 100644 crates/project/src/compile/mod.rs rename {src => crates/project/src}/compile/output/contracts.rs (98%) rename {src => crates/project/src}/compile/output/info.rs (100%) rename {src => crates/project/src}/compile/output/mod.rs (95%) rename {src => crates/project/src}/compile/output/sources.rs (100%) rename {src => crates/project/src}/compile/project.rs (98%) rename {src => crates/project/src}/compilers/mod.rs (96%) rename {src => crates/project/src}/compilers/multi.rs (94%) rename src/compile/mod.rs => crates/project/src/compilers/solc/compiler.rs (92%) rename src/compilers/solc.rs => crates/project/src/compilers/solc/mod.rs (89%) create mode 100644 crates/project/src/compilers/vyper/error.rs create mode 100644 crates/project/src/compilers/vyper/input.rs rename {src => crates/project/src}/compilers/vyper/mod.rs (95%) create mode 100644 crates/project/src/compilers/vyper/output.rs rename {src => crates/project/src}/compilers/vyper/parser.rs (98%) create mode 100644 crates/project/src/compilers/vyper/settings.rs rename {src => crates/project/src}/config.rs (99%) rename {src => crates/project/src}/filter.rs (99%) rename {src => crates/project/src}/flatten.rs (98%) rename {src => crates/project/src}/lib.rs (98%) rename {src => crates/project/src}/project_util/mock.rs (100%) rename {src => crates/project/src}/project_util/mod.rs (100%) rename {src => crates/project/src}/report/compiler.rs (99%) rename {src => crates/project/src}/report/mod.rs (99%) rename {src => crates/project/src}/resolver/mod.rs (99%) rename {src => crates/project/src}/resolver/parse.rs (90%) rename {src => crates/project/src}/resolver/tree.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 191d1855..0d2f34cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,8 @@ -[package] +[workspace] +members = ["crates/*"] +resolver = "2" + +[workspace.package] name = "foundry-compilers" authors = ["Foundry Maintainers"] version = "0.7.0" @@ -13,110 +17,18 @@ keywords = ["foundry", "solidity", "solc", "ethereum", "ethers"] edition = "2021" exclude = [".github/", "scripts/", "test-data/"] -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[package.metadata.playground] -all-features = true - -[dependencies] +[workspace.dependencies] +foundry-compilers-artifacts = { path = "crates/artifacts", version = "0.7.0" } +foundry-compilers-core = { path = "crates/core", version = "0.7.0" } +serde = { version = "1", features = ["derive", "rc"] } +semver = { version = "1.0", features = ["serde"] } +serde_json = "1.0" alloy-primitives = { version = "0.7", features = ["serde", "rand"] } alloy-json-abi = { version = "0.7", features = ["serde_json"] } - -solang-parser = { version = "=0.3.3", default-features = false } - -cfg-if = "1.0.0" -dirs = "5.0" -dunce = "1.0" -md-5 = "0.10" -memmap2 = "0.9" -once_cell = "1.19" -path-slash = "0.2" +tracing = "0.1" rayon = "1.8" +thiserror = "1" regex = "1.10" -semver = { version = "1.0", features = ["serde"] } -serde = { version = "1", features = ["derive", "rc"] } -serde_json = "1.0" -thiserror = "1.0" -tracing = "0.1" -walkdir = "2.4" -yansi = "1.0.1" - -# async -futures-util = { version = "0.3", optional = true } -tokio = { version = "1.35", features = ["rt-multi-thread"], optional = true } - -# project-util -tempfile = { version = "3.9", optional = true } -fs_extra = { version = "1.3", optional = true } -rand = { version = "0.8", optional = true } - -# svm -home = "0.5" -svm = { package = "svm-rs", version = "0.5", default-features = false, optional = true } -svm-builds = { package = "svm-rs-builds", version = "0.5", default-features = false, optional = true } -sha2 = { version = "0.10", default-features = false, optional = true } -itertools = "0.13" -auto_impl = "1" - -winnow = "0.6" -dyn-clone = "1" -derivative = "2.2" - -[dev-dependencies] -alloy-primitives = { version = "0.7", features = ["serde", "rand"] } -criterion = { version = "0.5", features = ["async_tokio"] } -pretty_assertions = "1" -rand = "0.8" -serde_path_to_error = "0.1" -tempfile = "3.9" -tokio = { version = "1.35", features = ["rt-multi-thread", "macros"] } -tracing-subscriber = { version = "0.3", default-features = false, features = [ - "env-filter", - "fmt", -] } -reqwest = "0.12" -fd-lock = "4.0.0" - -[[bench]] -name = "compile_many" -required-features = ["svm-solc"] -harness = false - -[[bench]] -name = "read_all" -required-features = ["project-util", "svm-solc"] -harness = false - -[[test]] -name = "project" -path = "tests/project.rs" -required-features = ["full", "project-util", "test-utils"] - -[[test]] -name = "mocked" -path = "tests/mocked.rs" -required-features = ["full", "project-util"] - -[features] -default = ["rustls"] -test-utils = [] - -full = ["async", "svm-solc"] - -# Adds extra `async` methods using `tokio` to some types. -async = [ - "dep:futures-util", - "dep:tokio", - "tokio/fs", - "tokio/process", - "tokio/io-util", -] -# Enables `svm` to auto-detect and manage `solc` builds. -svm-solc = ["dep:svm", "dep:svm-builds", "dep:sha2", "dep:tokio"] -# Utilities for creating and testing project workspaces. -project-util = ["dep:tempfile", "dep:fs_extra", "dep:rand", "svm-solc"] - -rustls = ["svm?/rustls"] -openssl = ["svm?/openssl"] +path-slash = "0.2" +md-5 = "0.10" +yansi = "1.0.1" \ No newline at end of file diff --git a/crates/artifacts/Cargo.toml b/crates/artifacts/Cargo.toml new file mode 100644 index 00000000..3d5107ce --- /dev/null +++ b/crates/artifacts/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "foundry-compilers-artifacts" +description = "Rust bindings for Solc and Vyper JSON artifacts" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +exclude.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[package.metadata.playground] +all-features = true + +[dependencies] +foundry-compilers-core.workspace = true + +serde.workspace = true +semver.workspace = true +serde_json.workspace = true +tracing.workspace = true +alloy-primitives.workspace = true +alloy-json-abi.workspace = true +rayon.workspace = true +thiserror.workspace = true +md-5.workspace = true +yansi.workspace = true + +walkdir = "2.4" diff --git a/src/artifacts/ast/lowfidelity.rs b/crates/artifacts/src/ast/lowfidelity.rs similarity index 99% rename from src/artifacts/ast/lowfidelity.rs rename to crates/artifacts/src/ast/lowfidelity.rs index 08017a9a..2f701a8a 100644 --- a/src/artifacts/ast/lowfidelity.rs +++ b/crates/artifacts/src/ast/lowfidelity.rs @@ -1,6 +1,6 @@ //! Bindings for solc's `ast` output field -use crate::artifacts::serde_helpers; +use crate::serde_helpers; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{collections::BTreeMap, fmt, fmt::Write, str::FromStr}; diff --git a/src/artifacts/ast/macros.rs b/crates/artifacts/src/ast/macros.rs similarity index 100% rename from src/artifacts/ast/macros.rs rename to crates/artifacts/src/ast/macros.rs diff --git a/src/artifacts/ast/misc.rs b/crates/artifacts/src/ast/misc.rs similarity index 100% rename from src/artifacts/ast/misc.rs rename to crates/artifacts/src/ast/misc.rs diff --git a/src/artifacts/ast/mod.rs b/crates/artifacts/src/ast/mod.rs similarity index 99% rename from src/artifacts/ast/mod.rs rename to crates/artifacts/src/ast/mod.rs index 0e60444a..1ab6bb49 100644 --- a/src/artifacts/ast/mod.rs +++ b/crates/artifacts/src/ast/mod.rs @@ -27,7 +27,7 @@ pub use lowfidelity::{Ast, Node, NodeType, SourceLocation as LowFidelitySourceLo /// The Yul AST is embedded into the Solidity AST for inline assembly blocks. pub mod yul; -use crate::artifacts::serde_helpers; +use crate::serde_helpers; use macros::{ast_node, expr_node, node_group, stmt_node}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; diff --git a/src/artifacts/ast/util.rs b/crates/artifacts/src/ast/util.rs similarity index 100% rename from src/artifacts/ast/util.rs rename to crates/artifacts/src/ast/util.rs diff --git a/src/artifacts/ast/visitor.rs b/crates/artifacts/src/ast/visitor.rs similarity index 100% rename from src/artifacts/ast/visitor.rs rename to crates/artifacts/src/ast/visitor.rs diff --git a/src/artifacts/ast/yul.rs b/crates/artifacts/src/ast/yul.rs similarity index 99% rename from src/artifacts/ast/yul.rs rename to crates/artifacts/src/ast/yul.rs index 556083cb..2b4ab9a3 100644 --- a/src/artifacts/ast/yul.rs +++ b/crates/artifacts/src/ast/yul.rs @@ -1,5 +1,5 @@ use super::{macros::node_group, misc::SourceLocation}; -use crate::artifacts::serde_helpers; +use crate::serde_helpers; use serde::{Deserialize, Serialize}; node_group! { diff --git a/src/artifacts/bytecode.rs b/crates/artifacts/src/bytecode.rs similarity index 99% rename from src/artifacts/bytecode.rs rename to crates/artifacts/src/bytecode.rs index 6651556c..0f1d43d0 100644 --- a/src/artifacts/bytecode.rs +++ b/crates/artifacts/src/bytecode.rs @@ -1,11 +1,12 @@ //! Bytecode related types. use crate::{ - artifacts::{serde_helpers, FunctionDebugData, GeneratedSource, Offsets}, + serde_helpers, sourcemap::{self, SourceMap, SyntaxError}, - utils, + FunctionDebugData, GeneratedSource, Offsets, }; use alloy_primitives::{hex, Address, Bytes}; +use foundry_compilers_core::utils; use serde::{Deserialize, Serialize, Serializer}; use std::collections::BTreeMap; diff --git a/src/artifacts/contract.rs b/crates/artifacts/src/contract.rs similarity index 99% rename from src/artifacts/contract.rs rename to crates/artifacts/src/contract.rs index acf09ee6..35f75d4e 100644 --- a/src/artifacts/contract.rs +++ b/crates/artifacts/src/contract.rs @@ -1,6 +1,6 @@ //! Contract related types. -use crate::artifacts::{ +use crate::{ bytecode::{ Bytecode, BytecodeObject, CompactBytecode, CompactDeployedBytecode, DeployedBytecode, }, diff --git a/src/artifacts/error.rs b/crates/artifacts/src/error.rs similarity index 100% rename from src/artifacts/error.rs rename to crates/artifacts/src/error.rs diff --git a/src/hh.rs b/crates/artifacts/src/hh.rs similarity index 52% rename from src/hh.rs rename to crates/artifacts/src/hh.rs index 2a662e07..975f17e4 100644 --- a/src/hh.rs +++ b/crates/artifacts/src/hh.rs @@ -1,18 +1,14 @@ //! Hardhat support use crate::{ - artifacts::{ - bytecode::{Bytecode, BytecodeObject, DeployedBytecode}, - contract::{CompactContract, CompactContractBytecode, Contract, ContractBytecode}, - CompactContractBytecodeCow, Offsets, - }, - ArtifactOutput, SourceFile, VersionedSourceFile, + Bytecode, BytecodeObject, CompactContract, CompactContractBytecode, CompactContractBytecodeCow, + ContractBytecode, DeployedBytecode, Offsets, }; use alloy_json_abi::JsonAbi; use serde::{Deserialize, Serialize}; -use std::{borrow::Cow, collections::btree_map::BTreeMap, path::Path}; +use std::{borrow::Cow, collections::btree_map::BTreeMap}; -const HH_ARTIFACT_VERSION: &str = "hh-sol-artifact-1"; +pub const HH_ARTIFACT_VERSION: &str = "hh-sol-artifact-1"; /// A hardhat artifact #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -88,76 +84,3 @@ impl From for CompactContractBytecode { c.into() } } - -/// Hardhat style artifacts handler -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] -pub struct HardhatArtifacts { - _priv: (), -} - -impl ArtifactOutput for HardhatArtifacts { - type Artifact = HardhatArtifact; - - fn contract_to_artifact( - &self, - file: &Path, - 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) = - if let Some(code) = evm.deployed_bytecode.and_then(|code| code.bytecode) { - (Some(code.object), code.link_references) - } else { - (None, Default::default()) - }; - - let (bytecode, link_ref) = if let Some(bc) = evm.bytecode { - (Some(bc.object), bc.link_references) - } else { - (None, Default::default()) - }; - - (bytecode, link_ref, deployed_bytecode, deployed_link_references) - } else { - (Default::default(), Default::default(), None, Default::default()) - }; - - HardhatArtifact { - format: HH_ARTIFACT_VERSION.to_string(), - contract_name: name.to_string(), - source_name: file.to_string_lossy().to_string(), - abi: contract.abi.unwrap_or_default(), - bytecode, - deployed_bytecode, - link_references, - deployed_link_references, - } - } - - fn standalone_source_file_to_artifact( - &self, - _path: &Path, - _file: &VersionedSourceFile, - ) -> Option { - None - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::Artifact; - - #[test] - fn can_parse_hh_artifact() { - let s = include_str!("../test-data/hh-greeter-artifact.json"); - let artifact = serde_json::from_str::(s).unwrap(); - let compact = artifact.into_compact_contract(); - assert!(compact.abi.is_some()); - assert!(compact.bin.is_some()); - assert!(compact.bin_runtime.is_some()); - } -} diff --git a/src/artifacts/mod.rs b/crates/artifacts/src/lib.rs similarity index 93% rename from src/artifacts/mod.rs rename to crates/artifacts/src/lib.rs index faec1435..6b015014 100644 --- a/src/artifacts/mod.rs +++ b/crates/artifacts/src/lib.rs @@ -2,37 +2,46 @@ #![allow(ambiguous_glob_reexports)] -use crate::{ - compile::*, compilers::solc::SolcLanguage, error::SolcIoError, output::ErrorFilter, - remappings::Remapping, utils, ProjectPathsConfig, SolcError, -}; -use alloy_primitives::hex; -use md5::Digest; +#[macro_use] +extern crate tracing; + use semver::Version; use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; use std::{ - collections::{BTreeMap, HashMap, HashSet}, - fmt, fs, + borrow::Cow, + collections::{BTreeMap, HashSet}, + fmt, path::{Path, PathBuf}, str::FromStr, - sync::Arc, }; pub mod error; pub use error::*; - pub mod ast; pub use ast::*; +pub mod remappings; +pub use remappings::*; pub mod bytecode; +pub use bytecode::*; pub mod contract; +pub use contract::*; +pub mod hh; pub mod output_selection; pub mod serde_helpers; +pub mod sourcemap; +pub mod sources; +pub mod vyper; use crate::{ - artifacts::output_selection::{ContractOutputSelection, OutputSelection}, - filter::FilteredSources, + output_selection::{ContractOutputSelection, OutputSelection}, + sources::{Source, Sources}, +}; +use foundry_compilers_core::{ + error::SolcError, + utils::{ + BERLIN_SOLC, BYZANTIUM_SOLC, CANCUN_SOLC, CONSTANTINOPLE_SOLC, ISTANBUL_SOLC, LONDON_SOLC, + PARIS_SOLC, PETERSBURG_SOLC, SHANGHAI_SOLC, + }, }; -pub use bytecode::*; -pub use contract::*; pub use serde_helpers::{deserialize_bytes, deserialize_opt_bytes}; /// Solidity files are made up of multiple `source units`, a solidity contract is such a `source @@ -45,18 +54,26 @@ pub type FileToContractsMap = BTreeMap>; /// file -> (contract name -> Contract) pub type Contracts = FileToContractsMap; -/// An ordered list of files and their source -pub type Sources = BTreeMap; - -/// A set of different Solc installations with their version and the sources to be compiled -pub(crate) type VersionedSources = HashMap>; - -/// A set of different Solc installations with their version and the sources to be compiled -pub(crate) type VersionedFilteredSources = HashMap>; - pub const SOLIDITY: &str = "Solidity"; pub const YUL: &str = "Yul"; +/// Languages supported by the Solc compiler. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[non_exhaustive] +pub enum SolcLanguage { + Solidity, + Yul, +} + +impl fmt::Display for SolcLanguage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Solidity => write!(f, "Solidity"), + Self::Yul => write!(f, "Yul"), + } + } +} + /// Input type `solc` expects. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SolcInput { @@ -599,9 +616,15 @@ impl Libraries { self.libs.len() } + /// Applies the given function to [Self] and returns the result. + pub fn apply Self>(self, f: F) -> Self { + f(self) + } + /// Solc expects the lib paths to match the global path after remappings were applied /// /// See also [ProjectPathsConfig::resolve_import] + #[cfg(ignore)] pub fn with_applied_remappings(mut self, config: &ProjectPathsConfig) -> Self { self.libs = self .libs @@ -624,7 +647,7 @@ impl Libraries { self.libs = self .libs .into_iter() - .map(|(f, l)| (utils::source_name(&f, base).to_path_buf(), l)) + .map(|(f, l)| (f.strip_prefix(base).unwrap_or(&f).to_path_buf(), l)) .collect(); self } @@ -1424,157 +1447,43 @@ pub struct DocLibraries { pub libs: BTreeMap, } -/// Content of a solidity file -/// -/// This contains the actual source code of a file -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct Source { - /// Content of the file - /// - /// This is an `Arc` because it may be cloned. If the [Graph](crate::resolver::Graph) of the - /// project contains multiple conflicting versions then the same [Source] may be required by - /// conflicting versions and needs to be duplicated. - pub content: Arc, +/// How to filter errors/warnings +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ErrorFilter<'a> { + /// Ignore errors/warnings with these codes + pub error_codes: Cow<'a, [u64]>, + /// Ignore errors/warnings from these file paths + pub ignored_file_paths: Cow<'a, [PathBuf]>, } -impl Source { - /// Creates a new instance of [Source] with the given content. - pub fn new(content: impl Into) -> Self { - Self { content: Arc::new(content.into()) } - } - - /// Reads the file's content - #[instrument(level = "debug", skip_all, err)] - pub fn read(file: impl AsRef) -> Result { - let file = file.as_ref(); - trace!(file=%file.display()); - let mut content = fs::read_to_string(file).map_err(|err| SolcIoError::new(err, file))?; - - // Normalize line endings to ensure deterministic metadata. - if content.contains('\r') { - content = content.replace("\r\n", "\n"); +impl<'a> ErrorFilter<'a> { + /// Creates a new `ErrorFilter` with the given error codes and ignored file paths + pub fn new(error_codes: &'a [u64], ignored_file_paths: &'a [PathBuf]) -> Self { + ErrorFilter { + error_codes: Cow::Borrowed(error_codes), + ignored_file_paths: Cow::Borrowed(ignored_file_paths), } - - Ok(Self::new(content)) - } - - /// Recursively finds all source files under the given dir path and reads them all - pub fn read_all_from( - dir: impl AsRef, - extensions: &[&str], - ) -> Result { - Self::read_all_files(utils::source_files(dir, extensions)) - } - - /// Recursively finds all solidity and yul files under the given dir path and reads them all - pub fn read_sol_yul_from(dir: impl AsRef) -> Result { - Self::read_all_from(dir, SOLC_EXTENSIONS) - } - - /// Reads all source files of the given vec - /// - /// Depending on the len of the vec it will try to read the files in parallel - pub fn read_all_files(files: Vec) -> Result { - Self::read_all(files) - } - - /// Reads all files - pub fn read_all(files: I) -> Result - where - I: IntoIterator, - T: Into, - { - files - .into_iter() - .map(Into::into) - .map(|file| Self::read(&file).map(|source| (file, source))) - .collect() - } - - /// Parallelized version of `Self::read_all` that reads all files using a parallel iterator - /// - /// NOTE: this is only expected to be faster than `Self::read_all` if the given iterator - /// contains at least several paths or the files are rather large. - pub fn par_read_all(files: I) -> Result - where - I: IntoIterator, - ::IntoIter: Send, - T: Into + Send, - { - use rayon::{iter::ParallelBridge, prelude::ParallelIterator}; - files - .into_iter() - .par_bridge() - .map(Into::into) - .map(|file| Self::read(&file).map(|source| (file, source))) - .collect() - } - - /// Generate a non-cryptographically secure checksum of the file's content - pub fn content_hash(&self) -> String { - let mut hasher = md5::Md5::new(); - hasher.update(self); - let result = hasher.finalize(); - hex::encode(result) - } - - /// Returns all import statements of the file - pub fn parse_imports(&self) -> Vec<&str> { - utils::find_import_paths(self.as_ref()).map(|m| m.as_str()).collect() } -} - -#[cfg(feature = "async")] -impl Source { - /// async version of `Self::read` - pub async fn async_read(file: impl AsRef) -> Result { - let file = file.as_ref(); - let mut content = - tokio::fs::read_to_string(file).await.map_err(|err| SolcIoError::new(err, file))?; - - // Normalize line endings to ensure deterministic metadata. - if content.contains('\r') { - content = content.replace("\r\n", "\n"); + /// Helper function to check if an error code is ignored + pub fn is_code_ignored(&self, code: Option) -> bool { + match code { + Some(code) => self.error_codes.contains(&code), + None => false, } - - Ok(Self::new(content)) - } - - /// Finds all source files under the given dir path and reads them all - pub async fn async_read_all_from( - dir: impl AsRef, - extensions: &[&str], - ) -> Result { - Self::async_read_all(utils::source_files(dir.as_ref(), extensions)).await - } - - /// async version of `Self::read_all` - pub async fn async_read_all(files: I) -> Result - where - I: IntoIterator, - T: Into, - { - futures_util::future::join_all( - files - .into_iter() - .map(Into::into) - .map(|file| async { Self::async_read(&file).await.map(|source| (file, source)) }), - ) - .await - .into_iter() - .collect() } -} -impl AsRef for Source { - fn as_ref(&self) -> &str { - &self.content + /// Helper function to check if an error's file path is ignored + pub fn is_file_ignored(&self, file_path: &Path) -> bool { + self.ignored_file_paths.iter().any(|ignored_path| file_path.starts_with(ignored_path)) } } -impl AsRef<[u8]> for Source { - fn as_ref(&self) -> &[u8] { - self.content.as_bytes() +impl<'a> From<&'a [u64]> for ErrorFilter<'a> { + fn from(error_codes: &'a [u64]) -> Self { + ErrorFilter { + error_codes: Cow::Borrowed(error_codes), + ignored_file_paths: Cow::Borrowed(&[]), + } } } diff --git a/src/artifacts/output_selection.rs b/crates/artifacts/src/output_selection.rs similarity index 100% rename from src/artifacts/output_selection.rs rename to crates/artifacts/src/output_selection.rs diff --git a/src/remappings.rs b/crates/artifacts/src/remappings.rs similarity index 99% rename from src/remappings.rs rename to crates/artifacts/src/remappings.rs index 4da3f961..89e4d178 100644 --- a/src/remappings.rs +++ b/crates/artifacts/src/remappings.rs @@ -1,4 +1,4 @@ -use crate::utils; +use foundry_compilers_core::utils; use serde::{Deserialize, Serialize}; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, diff --git a/src/artifacts/serde_helpers.rs b/crates/artifacts/src/serde_helpers.rs similarity index 100% rename from src/artifacts/serde_helpers.rs rename to crates/artifacts/src/serde_helpers.rs diff --git a/src/sourcemap.rs b/crates/artifacts/src/sourcemap.rs similarity index 100% rename from src/sourcemap.rs rename to crates/artifacts/src/sourcemap.rs diff --git a/crates/artifacts/src/sources.rs b/crates/artifacts/src/sources.rs new file mode 100644 index 00000000..b4e4a79e --- /dev/null +++ b/crates/artifacts/src/sources.rs @@ -0,0 +1,162 @@ +use alloy_primitives::hex; +use foundry_compilers_core::{error::SolcIoError, utils}; +use md5::Digest; +use serde::{Deserialize, Serialize}; +use std::{ + collections::BTreeMap, + fs, + path::{Path, PathBuf}, + sync::Arc, +}; + +/// An ordered list of files and their source +pub type Sources = BTreeMap; + +/// Content of a solidity file +/// +/// This contains the actual source code of a file +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] +pub struct Source { + /// Content of the file + /// + /// This is an `Arc` because it may be cloned. If the [Graph](crate::resolver::Graph) of the + /// project contains multiple conflicting versions then the same [Source] may be required by + /// conflicting versions and needs to be duplicated. + pub content: Arc, +} + +impl Source { + /// Creates a new instance of [Source] with the given content. + pub fn new(content: impl Into) -> Self { + Self { content: Arc::new(content.into()) } + } + + /// Reads the file's content + #[instrument(level = "debug", skip_all, err)] + pub fn read(file: impl AsRef) -> Result { + let file = file.as_ref(); + trace!(file=%file.display()); + let mut content = fs::read_to_string(file).map_err(|err| SolcIoError::new(err, file))?; + + // Normalize line endings to ensure deterministic metadata. + if content.contains('\r') { + content = content.replace("\r\n", "\n"); + } + + Ok(Self::new(content)) + } + + /// Recursively finds all source files under the given dir path and reads them all + pub fn read_all_from( + dir: impl AsRef, + extensions: &[&str], + ) -> Result { + Self::read_all_files(utils::source_files(dir, extensions)) + } + + /// Recursively finds all solidity and yul files under the given dir path and reads them all + pub fn read_sol_yul_from(dir: impl AsRef) -> Result { + Self::read_all_from(dir, utils::SOLC_EXTENSIONS) + } + + /// Reads all source files of the given vec + /// + /// Depending on the len of the vec it will try to read the files in parallel + pub fn read_all_files(files: Vec) -> Result { + Self::read_all(files) + } + + /// Reads all files + pub fn read_all(files: I) -> Result + where + I: IntoIterator, + T: Into, + { + files + .into_iter() + .map(Into::into) + .map(|file| Self::read(&file).map(|source| (file, source))) + .collect() + } + + /// Parallelized version of `Self::read_all` that reads all files using a parallel iterator + /// + /// NOTE: this is only expected to be faster than `Self::read_all` if the given iterator + /// contains at least several paths or the files are rather large. + pub fn par_read_all(files: I) -> Result + where + I: IntoIterator, + ::IntoIter: Send, + T: Into + Send, + { + use rayon::{iter::ParallelBridge, prelude::ParallelIterator}; + files + .into_iter() + .par_bridge() + .map(Into::into) + .map(|file| Self::read(&file).map(|source| (file, source))) + .collect() + } + + /// Generate a non-cryptographically secure checksum of the file's content + pub fn content_hash(&self) -> String { + let mut hasher = md5::Md5::new(); + hasher.update(self); + let result = hasher.finalize(); + hex::encode(result) + } +} + +#[cfg(feature = "async")] +impl Source { + /// async version of `Self::read` + pub async fn async_read(file: impl AsRef) -> Result { + let file = file.as_ref(); + let mut content = + tokio::fs::read_to_string(file).await.map_err(|err| SolcIoError::new(err, file))?; + + // Normalize line endings to ensure deterministic metadata. + if content.contains('\r') { + content = content.replace("\r\n", "\n"); + } + + Ok(Self::new(content)) + } + + /// Finds all source files under the given dir path and reads them all + pub async fn async_read_all_from( + dir: impl AsRef, + extensions: &[&str], + ) -> Result { + Self::async_read_all(utils::source_files(dir.as_ref(), extensions)).await + } + + /// async version of `Self::read_all` + pub async fn async_read_all(files: I) -> Result + where + I: IntoIterator, + T: Into, + { + futures_util::future::join_all( + files + .into_iter() + .map(Into::into) + .map(|file| async { Self::async_read(&file).await.map(|source| (file, source)) }), + ) + .await + .into_iter() + .collect() + } +} + +impl AsRef for Source { + fn as_ref(&self) -> &str { + &self.content + } +} + +impl AsRef<[u8]> for Source { + fn as_ref(&self) -> &[u8] { + self.content.as_bytes() + } +} diff --git a/src/compilers/vyper/error.rs b/crates/artifacts/src/vyper/error.rs similarity index 71% rename from src/compilers/vyper/error.rs rename to crates/artifacts/src/vyper/error.rs index 8afd87ec..bd037549 100644 --- a/src/compilers/vyper/error.rs +++ b/crates/artifacts/src/vyper/error.rs @@ -1,11 +1,7 @@ +use crate::Severity; use core::fmt; -use std::path::PathBuf; - -use crate::{ - artifacts::{error::SourceLocation, Severity}, - compilers::CompilationError, -}; use serde::{Deserialize, Serialize}; +use std::path::PathBuf; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct VyperSourceLocation { @@ -25,28 +21,6 @@ pub struct VyperCompilationError { pub formatted_message: Option, } -impl CompilationError for VyperCompilationError { - fn is_warning(&self) -> bool { - self.severity.is_warning() - } - - fn is_error(&self) -> bool { - self.severity.is_error() - } - - fn source_location(&self) -> Option { - None - } - - fn severity(&self) -> Severity { - self.severity - } - - fn error_code(&self) -> Option { - None - } -} - impl fmt::Display for VyperCompilationError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(location) = &self.source_location { diff --git a/src/compilers/vyper/input.rs b/crates/artifacts/src/vyper/input.rs similarity index 54% rename from src/compilers/vyper/input.rs rename to crates/artifacts/src/vyper/input.rs index 03e7ff02..8488b53d 100644 --- a/src/compilers/vyper/input.rs +++ b/crates/artifacts/src/vyper/input.rs @@ -1,13 +1,12 @@ -use std::{borrow::Cow, path::Path}; +use std::path::Path; -use super::{settings::VyperSettings, VyperLanguage, VYPER_INTERFACE_EXTENSION}; -use crate::{ - artifacts::{Source, Sources}, - compilers::CompilerInput, -}; -use semver::Version; +use super::VyperSettings; +use crate::sources::Sources; use serde::{Deserialize, Serialize}; +/// Extension of Vyper interface file. +pub const VYPER_INTERFACE_EXTENSION: &str = "vyi"; + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct VyperInput { pub language: String, @@ -16,14 +15,6 @@ pub struct VyperInput { pub settings: VyperSettings, } -#[derive(Debug, Clone, Serialize)] -pub struct VyperVersionedInput { - #[serde(flatten)] - pub input: VyperInput, - #[serde(skip)] - pub version: Version, -} - impl VyperInput { pub fn new(sources: Sources, mut settings: VyperSettings) -> Self { let mut new_sources = Sources::new(); @@ -57,41 +48,3 @@ impl VyperInput { self.settings.strip_prefix(base) } } - -impl CompilerInput for VyperVersionedInput { - type Settings = VyperSettings; - type Language = VyperLanguage; - - fn build( - sources: Sources, - settings: Self::Settings, - _language: Self::Language, - version: Version, - ) -> Self { - Self { input: VyperInput::new(sources, settings), version } - } - - fn compiler_name(&self) -> Cow<'static, str> { - "Vyper".into() - } - - fn strip_prefix(&mut self, base: &Path) { - self.input.strip_prefix(base); - } - - fn language(&self) -> Self::Language { - VyperLanguage - } - - fn version(&self) -> &Version { - &self.version - } - - fn sources(&self) -> impl Iterator { - self.input - .sources - .iter() - .chain(self.input.interfaces.iter()) - .map(|(path, source)| (path.as_path(), source)) - } -} diff --git a/crates/artifacts/src/vyper/mod.rs b/crates/artifacts/src/vyper/mod.rs new file mode 100644 index 00000000..e1186bc0 --- /dev/null +++ b/crates/artifacts/src/vyper/mod.rs @@ -0,0 +1,11 @@ +pub mod settings; +pub use settings::{VyperOptimizationMode, VyperSettings}; + +pub mod error; +pub use error::VyperCompilationError; + +pub mod input; +pub use input::VyperInput; + +pub mod output; +pub use output::VyperOutput; diff --git a/src/compilers/vyper/output.rs b/crates/artifacts/src/vyper/output.rs similarity index 87% rename from src/compilers/vyper/output.rs rename to crates/artifacts/src/vyper/output.rs index 81d26b56..330b43b4 100644 --- a/src/compilers/vyper/output.rs +++ b/crates/artifacts/src/vyper/output.rs @@ -1,5 +1,5 @@ -use super::VyperCompilationError; -use crate::artifacts::{BytecodeObject, Contract, Evm, FileToContractsMap, SourceFile}; +use super::error::VyperCompilationError; +use crate::{BytecodeObject, Contract, Evm, FileToContractsMap, SourceFile}; use alloy_json_abi::JsonAbi; use alloy_primitives::Bytes; use serde::Deserialize; @@ -19,9 +19,9 @@ pub struct Bytecode { pub source_map: Option, } -impl From for crate::artifacts::Bytecode { +impl From for crate::Bytecode { fn from(bytecode: Bytecode) -> Self { - crate::artifacts::Bytecode { + crate::Bytecode { object: BytecodeObject::Bytecode(bytecode.object), opcodes: bytecode.opcodes, source_map: bytecode.source_map, @@ -48,7 +48,7 @@ impl From for Evm { fn from(evm: VyperEvm) -> Self { Evm { bytecode: evm.bytecode.map(Into::into), - deployed_bytecode: evm.deployed_bytecode.map(|b| crate::artifacts::DeployedBytecode { + deployed_bytecode: evm.deployed_bytecode.map(|b| crate::DeployedBytecode { bytecode: Some(b.into()), immutable_references: Default::default(), }), @@ -124,20 +124,6 @@ impl VyperOutput { } } -impl From for super::CompilerOutput { - fn from(output: VyperOutput) -> Self { - super::CompilerOutput { - errors: output.errors, - contracts: output - .contracts - .into_iter() - .map(|(k, v)| (k, v.into_iter().map(|(k, v)| (k, v.into())).collect())) - .collect(), - sources: output.sources.into_iter().map(|(k, v)| (k, v.into())).collect(), - } - } -} - /// Before Vyper 0.4 source map was represented as a string, after 0.4 it is represented as a map /// where compressed source map is stored under `pc_pos_map_compressed` key. fn deserialize_vyper_sourcemap<'de, D>(deserializer: D) -> Result, D::Error> diff --git a/src/compilers/vyper/settings.rs b/crates/artifacts/src/vyper/settings.rs similarity index 75% rename from src/compilers/vyper/settings.rs rename to crates/artifacts/src/vyper/settings.rs index 81dabf2d..49142e26 100644 --- a/src/compilers/vyper/settings.rs +++ b/crates/artifacts/src/vyper/settings.rs @@ -1,11 +1,6 @@ -use std::path::Path; - -use crate::{ - artifacts::{output_selection::OutputSelection, serde_helpers}, - compilers::CompilerSettings, - EvmVersion, -}; +use crate::{output_selection::OutputSelection, serde_helpers, EvmVersion}; use serde::{Deserialize, Serialize}; +use std::path::Path; #[derive(Debug, Serialize, Clone, Copy, Deserialize, Eq, PartialEq)] #[serde(rename_all = "lowercase")] @@ -66,17 +61,3 @@ impl VyperSettings { }); } } - -impl CompilerSettings for VyperSettings { - fn update_output_selection(&mut self, f: impl FnOnce(&mut OutputSelection)) { - f(&mut self.output_selection) - } - - fn can_use_cached(&self, other: &Self) -> bool { - let Self { evm_version, optimize, bytecode_metadata, output_selection } = self; - evm_version == &other.evm_version - && optimize == &other.optimize - && bytecode_metadata == &other.bytecode_metadata - && output_selection.is_subset_of(&other.output_selection) - } -} diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml new file mode 100644 index 00000000..28a48814 --- /dev/null +++ b/crates/core/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "foundry-compilers-core" +description = "Rust bindings for Solc and Vyper JSON artifacts" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +exclude.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[package.metadata.playground] +all-features = true + +[dependencies] +thiserror.workspace = true +semver.workspace = true +serde.workspace = true +serde_json.workspace = true +regex.workspace = true +path-slash.workspace = true +alloy-primitives.workspace = true + +walkdir = "2.4" +dunce = "1.0" +memmap2 = "0.9" +cfg-if = "1.0.0" +once_cell = "1.19" \ No newline at end of file diff --git a/src/error.rs b/crates/core/src/error.rs similarity index 96% rename from src/error.rs rename to crates/core/src/error.rs index db3b3955..8f98e5d5 100644 --- a/src/error.rs +++ b/crates/core/src/error.rs @@ -74,12 +74,12 @@ pub enum SolcError { } impl SolcError { - pub(crate) fn io(err: io::Error, path: impl Into) -> Self { + pub fn io(err: io::Error, path: impl Into) -> Self { SolcIoError::new(err, path).into() } /// Create an error from the Solc executable's output. - pub(crate) fn solc_output(output: &std::process::Output) -> Self { + pub fn solc_output(output: &std::process::Output) -> Self { let mut msg = String::from_utf8_lossy(&output.stderr); let mut trimmed = msg.trim(); if trimmed.is_empty() { diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs new file mode 100644 index 00000000..caf91b35 --- /dev/null +++ b/crates/core/src/lib.rs @@ -0,0 +1,2 @@ +pub mod error; +pub mod utils; diff --git a/src/utils.rs b/crates/core/src/utils.rs similarity index 90% rename from src/utils.rs rename to crates/core/src/utils.rs index 6435ff07..952f131b 100644 --- a/src/utils.rs +++ b/crates/core/src/utils.rs @@ -1,11 +1,11 @@ //! Utility functions -use crate::{error::SolcError, SolcIoError, SOLC_EXTENSIONS}; +use crate::error::{SolcError, SolcIoError}; use alloy_primitives::{hex, keccak256}; use cfg_if::cfg_if; use once_cell::sync::Lazy; use regex::{Match, Regex}; -use semver::Version; +use semver::{Version, VersionReq}; use serde::{de::DeserializeOwned, Serialize}; use std::{ collections::HashSet, @@ -46,6 +46,53 @@ pub static RE_THREE_OR_MORE_NEWLINES: Lazy = Lazy::new(|| Regex::new("\n{ pub static RE_VYPER_VERSION: Lazy = Lazy::new(|| Regex::new(r"#(?:pragma version|@version)\s+(?P.+)").unwrap()); +/// Extensions acceptable by solc compiler. +pub const SOLC_EXTENSIONS: &[&str] = &["sol", "yul"]; + +/// Support for configuring the EVM version +/// +pub const BYZANTIUM_SOLC: Version = Version::new(0, 4, 21); + +/// Bug fix for configuring the EVM version with Constantinople +/// +pub const CONSTANTINOPLE_SOLC: Version = Version::new(0, 4, 22); + +/// Petersburg support +/// +pub const PETERSBURG_SOLC: Version = Version::new(0, 5, 5); + +/// Istanbul support +/// +pub const ISTANBUL_SOLC: Version = Version::new(0, 5, 14); + +/// Berlin support +/// +pub const BERLIN_SOLC: Version = Version::new(0, 8, 5); + +/// London support +/// +pub const LONDON_SOLC: Version = Version::new(0, 8, 7); + +/// Paris support +/// +pub const PARIS_SOLC: Version = Version::new(0, 8, 18); + +/// Shanghai support +/// +pub const SHANGHAI_SOLC: Version = Version::new(0, 8, 20); + +/// Cancun support +/// +pub const CANCUN_SOLC: Version = Version::new(0, 8, 24); + +// `--base-path` was introduced in 0.6.9 +pub static SUPPORTS_BASE_PATH: Lazy = + Lazy::new(|| VersionReq::parse(">=0.6.9").unwrap()); + +// `--include-path` was introduced in 0.8.8 +pub static SUPPORTS_INCLUDE_PATH: Lazy = + Lazy::new(|| VersionReq::parse(">=0.8.8").unwrap()); + /// Create a regex that matches any library or contract name inside a file pub fn create_contract_or_lib_name_regex(name: &str) -> Regex { Regex::new(&format!(r#"(?:using\s+(?P{name})\s+|is\s+(?:\w+\s*,\s*)*(?P{name})(?:\s*,\s*\w+)*|(?:(?P(?:function|error|as)\s+|\n[^\n]*(?:"([^"\n]|\\")*|'([^'\n]|\\')*))|\W+)(?P{name})(?:\.|\(| ))"#)).unwrap() @@ -182,7 +229,7 @@ pub fn canonicalize(path: impl AsRef) -> Result { PathBuf::from(p.to_slash_lossy().as_ref()) }); } else { - let res = dunce::canonicalize(path); + let res = dunce::canonicalize(path); } }; @@ -456,7 +503,7 @@ pub fn common_ancestor(a: impl AsRef, b: impl AsRef) -> Option/` if it exists or `/` does not exist, /// Returns `/` if it exists and `/` does not exist. -pub(crate) fn find_fave_or_alt_path(root: impl AsRef, fave: &str, alt: &str) -> PathBuf { +pub fn find_fave_or_alt_path(root: impl AsRef, fave: &str, alt: &str) -> PathBuf { let root = root.as_ref(); let p = root.join(fave); if !p.exists() { @@ -469,7 +516,7 @@ pub(crate) fn find_fave_or_alt_path(root: impl AsRef, fave: &str, alt: &st } /// Attempts to find a file with different case that exists next to the `non_existing` file -pub(crate) fn find_case_sensitive_existing_file(non_existing: &Path) -> Option { +pub fn find_case_sensitive_existing_file(non_existing: &Path) -> Option { let non_existing_file_name = non_existing.file_name()?; let parent = non_existing.parent()?; WalkDir::new(parent) @@ -567,6 +614,27 @@ pub fn create_parent_dir_all(file: impl AsRef) -> Result<(), SolcError> { Ok(()) } +/// Given the regex and the target string, find all occurrences +/// of named groups within the string. This method returns +/// the tuple of matches `(a, b)` where `a` is the match for the +/// entire regex and `b` is the match for the first named group. +/// +/// NOTE: This method will return the match for the first named +/// group, so the order of passed named groups matters. +pub fn capture_outer_and_inner<'a>( + content: &'a str, + regex: ®ex::Regex, + names: &[&str], +) -> Vec<(regex::Match<'a>, regex::Match<'a>)> { + regex + .captures_iter(content) + .filter_map(|cap| { + let cap_match = names.iter().find_map(|name| cap.name(name)); + cap_match.and_then(|m| cap.get(0).map(|outer| (outer.to_owned(), m))) + }) + .collect() +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml new file mode 100644 index 00000000..008a1987 --- /dev/null +++ b/crates/project/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "foundry-compilers-project" +description = "Compiler abstraction and implementations for Solc and Vyper" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +exclude.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[package.metadata.playground] +all-features = true + +[dependencies] +foundry-compilers-artifacts.workspace = true +foundry-compilers-core.workspace = true +serde.workspace = true +semver.workspace = true +alloy-primitives.workspace = true +serde_json.workspace = true +tracing.workspace = true +alloy-json-abi.workspace = true +rayon.workspace = true +md-5.workspace = true +thiserror.workspace = true +path-slash.workspace = true +yansi.workspace = true + +auto_impl = "1" +winnow = "0.6" +dyn-clone = "1" +derivative = "2.2" +solang-parser = { version = "=0.3.3", default-features = false } +home = "0.5" +dirs = "5.0" +itertools = "0.13" \ No newline at end of file diff --git a/crates/project/LICENSE-APACHE b/crates/project/LICENSE-APACHE new file mode 100644 index 00000000..d9a10c0d --- /dev/null +++ b/crates/project/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/crates/project/LICENSE-MIT b/crates/project/LICENSE-MIT new file mode 100644 index 00000000..cb2a219b --- /dev/null +++ b/crates/project/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2020 Georgios Konstantopoulos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/project/README.md b/crates/project/README.md new file mode 100644 index 00000000..e69de29b diff --git a/src/artifact_output/configurable.rs b/crates/project/src/artifact_output/configurable.rs similarity index 97% rename from src/artifact_output/configurable.rs rename to crates/project/src/artifact_output/configurable.rs index ced84ff1..6fab70d5 100644 --- a/src/artifact_output/configurable.rs +++ b/crates/project/src/artifact_output/configurable.rs @@ -9,22 +9,23 @@ //! that some output values can also be emitted as standalone files. use crate::{ - artifacts::{ - bytecode::{CompactBytecode, CompactDeployedBytecode}, - contract::{CompactContract, CompactContractBytecode, Contract}, - output_selection::{ - BytecodeOutputSelection, ContractOutputSelection, DeployedBytecodeOutputSelection, - EvmOutputSelection, EwasmOutputSelection, - }, - Ast, BytecodeObject, CompactContractBytecodeCow, DevDoc, Evm, Ewasm, FunctionDebugData, - GasEstimates, GeneratedSource, LosslessMetadata, Metadata, Offsets, Settings, - StorageLayout, UserDoc, - }, - sources::VersionedSourceFile, - utils, Artifact, ArtifactFile, ArtifactOutput, SolcConfig, SolcError, SourceFile, + sources::VersionedSourceFile, Artifact, ArtifactFile, ArtifactOutput, SolcConfig, SolcError, + SourceFile, }; use alloy_json_abi::JsonAbi; use alloy_primitives::hex; +use foundry_compilers_artifacts::{ + bytecode::{CompactBytecode, CompactDeployedBytecode}, + contract::{CompactContract, CompactContractBytecode, Contract}, + output_selection::{ + BytecodeOutputSelection, ContractOutputSelection, DeployedBytecodeOutputSelection, + EvmOutputSelection, EwasmOutputSelection, + }, + Ast, BytecodeObject, CompactContractBytecodeCow, DevDoc, Evm, Ewasm, FunctionDebugData, + GasEstimates, GeneratedSource, LosslessMetadata, Metadata, Offsets, Settings, StorageLayout, + UserDoc, +}; +use foundry_compilers_core::utils; use serde::{Deserialize, Serialize}; use std::{borrow::Cow, collections::BTreeMap, fs, path::Path}; @@ -237,7 +238,7 @@ impl ArtifactOutput for ConfigurableArtifacts { /// Writes extra files for compiled artifact based on [Self::additional_files] fn handle_artifacts( &self, - contracts: &crate::contracts::VersionedContracts, + contracts: &crate::VersionedContracts, artifacts: &crate::Artifacts, ) -> Result<(), SolcError> { for (file, contracts) in contracts.as_ref().iter() { diff --git a/crates/project/src/artifact_output/hh.rs b/crates/project/src/artifact_output/hh.rs new file mode 100644 index 00000000..1727b0f0 --- /dev/null +++ b/crates/project/src/artifact_output/hh.rs @@ -0,0 +1,79 @@ +use crate::{output::sources::VersionedSourceFile, ArtifactOutput}; +use foundry_compilers_artifacts::{ + hh::{HardhatArtifact, HH_ARTIFACT_VERSION}, + Contract, SourceFile, +}; +use std::path::Path; + +/// Hardhat style artifacts handler +#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] +pub struct HardhatArtifacts { + _priv: (), +} + +impl ArtifactOutput for HardhatArtifacts { + type Artifact = HardhatArtifact; + + fn contract_to_artifact( + &self, + file: &Path, + 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) = + if let Some(code) = evm.deployed_bytecode.and_then(|code| code.bytecode) { + (Some(code.object), code.link_references) + } else { + (None, Default::default()) + }; + + let (bytecode, link_ref) = if let Some(bc) = evm.bytecode { + (Some(bc.object), bc.link_references) + } else { + (None, Default::default()) + }; + + (bytecode, link_ref, deployed_bytecode, deployed_link_references) + } else { + (Default::default(), Default::default(), None, Default::default()) + }; + + HardhatArtifact { + format: HH_ARTIFACT_VERSION.to_string(), + contract_name: name.to_string(), + source_name: file.to_string_lossy().to_string(), + abi: contract.abi.unwrap_or_default(), + bytecode, + deployed_bytecode, + link_references, + deployed_link_references, + } + } + + fn standalone_source_file_to_artifact( + &self, + _path: &Path, + _file: &VersionedSourceFile, + ) -> Option { + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::Artifact; + + #[test] + fn can_parse_hh_artifact() { + let s = include_str!("../test-data/hh-greeter-artifact.json"); + let artifact = serde_json::from_str::(s).unwrap(); + let compact = artifact.into_compact_contract(); + assert!(compact.abi.is_some()); + assert!(compact.bin.is_some()); + assert!(compact.bin_runtime.is_some()); + } +} diff --git a/src/artifact_output/mod.rs b/crates/project/src/artifact_output/mod.rs similarity index 98% rename from src/artifact_output/mod.rs rename to crates/project/src/artifact_output/mod.rs index 474f4c58..6d4b2e76 100644 --- a/src/artifact_output/mod.rs +++ b/crates/project/src/artifact_output/mod.rs @@ -1,20 +1,17 @@ //! Output artifact handling -use crate::{ - artifacts::{ - contract::{CompactContract, CompactContractBytecode, Contract}, - BytecodeObject, CompactBytecode, CompactContractBytecodeCow, CompactDeployedBytecode, - FileToContractsMap, SourceFile, - }, - cache::CachedArtifact, - compile::output::{contracts::VersionedContracts, sources::VersionedSourceFiles}, - error::Result, - sourcemap::{SourceMap, SyntaxError}, - sources::VersionedSourceFile, - utils, CompilerCache, HardhatArtifact, ProjectPathsConfig, SolcError, SolcIoError, -}; use alloy_json_abi::JsonAbi; use alloy_primitives::Bytes; +use foundry_compilers_artifacts::{ + hh::HardhatArtifact, + sourcemap::{SourceMap, SyntaxError}, + BytecodeObject, CompactBytecode, CompactContract, CompactContractBytecode, + CompactContractBytecodeCow, CompactDeployedBytecode, Contract, FileToContractsMap, SourceFile, +}; +use foundry_compilers_core::{ + error::{Result, SolcError, SolcIoError}, + utils, +}; use path_slash::PathBufExt; use semver::Version; use serde::{de::DeserializeOwned, Deserialize, Serialize}; @@ -31,6 +28,18 @@ use std::{ mod configurable; pub use configurable::*; +mod hh; +pub use hh::*; + +use crate::{ + cache::{CachedArtifact, CompilerCache}, + output::{ + contracts::VersionedContracts, + sources::{VersionedSourceFile, VersionedSourceFiles}, + }, + ProjectPathsConfig, +}; + /// Represents unique artifact metadata for identifying artifacts on output #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct ArtifactId { @@ -779,7 +788,7 @@ pub trait ArtifactOutput { /// - The file does not exist /// - The file's content couldn't be deserialized into the `Artifact` type fn read_cached_artifact(path: impl AsRef) -> Result { - crate::utils::read_json_file(path) + utils::read_json_file(path) } /// Read the cached artifacts that are located the paths the iterator yields diff --git a/src/buildinfo.rs b/crates/project/src/buildinfo.rs similarity index 97% rename from src/buildinfo.rs rename to crates/project/src/buildinfo.rs index 31562f88..a0bd00d4 100644 --- a/src/buildinfo.rs +++ b/crates/project/src/buildinfo.rs @@ -1,11 +1,8 @@ //! Represents an entire build -use crate::{ - compilers::{CompilationError, CompilerInput, CompilerOutput, Language}, - error::Result, - utils, -}; +use crate::compilers::{CompilationError, CompilerInput, CompilerOutput, Language}; use alloy_primitives::hex; +use foundry_compilers_core::{error::Result, utils}; use md5::Digest; use semver::Version; use serde::{de::DeserializeOwned, Deserialize, Serialize}; diff --git a/src/cache.rs b/crates/project/src/cache.rs similarity index 99% rename from src/cache.rs rename to crates/project/src/cache.rs index eca71e2c..b0dc7ea0 100644 --- a/src/cache.rs +++ b/crates/project/src/cache.rs @@ -1,16 +1,20 @@ //! Support for compiling contracts. use crate::{ - artifacts::{Settings, Sources}, buildinfo::RawBuildInfo, compilers::{Compiler, CompilerSettings, Language}, - config::ProjectPaths, - error::{Result, SolcError}, - filter::{FilteredSources, SourceCompilationKind}, output::Builds, resolver::GraphEdges, - utils, ArtifactFile, ArtifactOutput, Artifacts, ArtifactsMap, Graph, OutputContext, Project, - ProjectPathsConfig, Source, + ArtifactFile, ArtifactOutput, Artifacts, ArtifactsMap, FilteredSources, Graph, OutputContext, + Project, ProjectPaths, ProjectPathsConfig, SourceCompilationKind, +}; +use foundry_compilers_artifacts::{ + sources::{Source, Sources}, + Settings, +}; +use foundry_compilers_core::{ + error::{Result, SolcError}, + utils, }; use semver::Version; use serde::{de::DeserializeOwned, Deserialize, Serialize}; diff --git a/src/compile/many.rs b/crates/project/src/compile/many.rs similarity index 88% rename from src/compile/many.rs rename to crates/project/src/compile/many.rs index 1f7e6ec4..180c19cb 100644 --- a/src/compile/many.rs +++ b/crates/project/src/compile/many.rs @@ -1,4 +1,7 @@ -use crate::{error::Result, CompilerOutput, Solc, SolcInput}; +use foundry_compilers_artifacts::{CompilerOutput, SolcInput}; +use foundry_compilers_core::error::Result; + +use crate::compilers::solc::compiler::Solc; /// The result of a `solc` process bundled with its `Solc` and `CompilerInput` type CompileElement = (Result, Solc, SolcInput); diff --git a/crates/project/src/compile/mod.rs b/crates/project/src/compile/mod.rs new file mode 100644 index 00000000..a577eb8e --- /dev/null +++ b/crates/project/src/compile/mod.rs @@ -0,0 +1,6 @@ +pub mod many; + +pub mod output; +pub use output::{contracts, info, sources}; + +pub mod project; diff --git a/src/compile/output/contracts.rs b/crates/project/src/compile/output/contracts.rs similarity index 98% rename from src/compile/output/contracts.rs rename to crates/project/src/compile/output/contracts.rs index 626fd038..1a6f5227 100644 --- a/src/compile/output/contracts.rs +++ b/crates/project/src/compile/output/contracts.rs @@ -1,9 +1,6 @@ -use crate::{ - artifacts::{ - contract::{CompactContractRef, Contract}, - CompactContractBytecode, FileToContractsMap, - }, - ArtifactId, +use crate::ArtifactId; +use foundry_compilers_artifacts::{ + CompactContractBytecode, CompactContractRef, Contract, FileToContractsMap, }; use semver::Version; use serde::{Deserialize, Deserializer, Serialize, Serializer}; diff --git a/src/compile/output/info.rs b/crates/project/src/compile/output/info.rs similarity index 100% rename from src/compile/output/info.rs rename to crates/project/src/compile/output/info.rs diff --git a/src/compile/output/mod.rs b/crates/project/src/compile/output/mod.rs similarity index 95% rename from src/compile/output/mod.rs rename to crates/project/src/compile/output/mod.rs index cd24f915..5932fae3 100644 --- a/src/compile/output/mod.rs +++ b/crates/project/src/compile/output/mod.rs @@ -1,22 +1,14 @@ //! The output of a compiled project - -use crate::{ - artifacts::{ - contract::{CompactContractBytecode, CompactContractRef, Contract}, - Severity, - }, - buildinfo::{BuildContext, RawBuildInfo}, - compilers::{multi::MultiCompiler, CompilationError, Compiler, CompilerOutput}, - error::SolcError, - info::ContractInfoRef, - sources::{VersionedSourceFile, VersionedSourceFiles}, - Artifact, ArtifactId, ArtifactOutput, Artifacts, ConfigurableArtifacts, SolcIoError, -}; use contracts::{VersionedContract, VersionedContracts}; +use foundry_compilers_artifacts::{ + CompactContractBytecode, CompactContractRef, Contract, ErrorFilter, Severity, +}; +use foundry_compilers_core::error::{SolcError, SolcIoError}; +use info::ContractInfoRef; use semver::Version; use serde::{Deserialize, Serialize}; +use sources::{VersionedSourceFile, VersionedSourceFiles}; use std::{ - borrow::Cow, collections::BTreeMap, fmt, ops::{Deref, DerefMut}, @@ -24,6 +16,12 @@ use std::{ }; use yansi::Paint; +use crate::{ + buildinfo::{BuildContext, RawBuildInfo}, + compilers::{multi::MultiCompiler, CompilationError, Compiler, CompilerOutput}, + Artifact, ArtifactId, ArtifactOutput, Artifacts, ConfigurableArtifacts, +}; + pub mod contracts; pub mod info; pub mod sources; @@ -557,46 +555,6 @@ impl Default for AggregatedCompilerOutput { } } -/// How to filter errors/warnings -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ErrorFilter<'a> { - /// Ignore errors/warnings with these codes - pub error_codes: Cow<'a, [u64]>, - /// Ignore errors/warnings from these file paths - pub ignored_file_paths: Cow<'a, [PathBuf]>, -} - -impl<'a> ErrorFilter<'a> { - /// Creates a new `ErrorFilter` with the given error codes and ignored file paths - pub fn new(error_codes: &'a [u64], ignored_file_paths: &'a [PathBuf]) -> Self { - ErrorFilter { - error_codes: Cow::Borrowed(error_codes), - ignored_file_paths: Cow::Borrowed(ignored_file_paths), - } - } - /// Helper function to check if an error code is ignored - pub fn is_code_ignored(&self, code: Option) -> bool { - match code { - Some(code) => self.error_codes.contains(&code), - None => false, - } - } - - /// Helper function to check if an error's file path is ignored - pub fn is_file_ignored(&self, file_path: &Path) -> bool { - self.ignored_file_paths.iter().any(|ignored_path| file_path.starts_with(ignored_path)) - } -} - -impl<'a> From<&'a [u64]> for ErrorFilter<'a> { - fn from(error_codes: &'a [u64]) -> Self { - ErrorFilter { - error_codes: Cow::Borrowed(error_codes), - ignored_file_paths: Cow::Borrowed(&[]), - } - } -} - impl AggregatedCompilerOutput { /// Converts all `\\` separators in _all_ paths to `/` pub fn slash_paths(&mut self) { diff --git a/src/compile/output/sources.rs b/crates/project/src/compile/output/sources.rs similarity index 100% rename from src/compile/output/sources.rs rename to crates/project/src/compile/output/sources.rs diff --git a/src/compile/project.rs b/crates/project/src/compile/project.rs similarity index 98% rename from src/compile/project.rs rename to crates/project/src/compile/project.rs index 7f1def72..1d8bd048 100644 --- a/src/compile/project.rs +++ b/crates/project/src/compile/project.rs @@ -102,19 +102,25 @@ use crate::{ artifact_output::Artifacts, - artifacts::{VersionedFilteredSources, VersionedSources}, buildinfo::RawBuildInfo, cache::ArtifactsCache, compilers::{Compiler, CompilerInput, CompilerOutput, Language}, - error::Result, filter::SparseOutputFilter, output::{AggregatedCompilerOutput, Builds}, report, resolver::GraphEdges, - ArtifactOutput, Graph, Project, ProjectCompileOutput, Sources, + ArtifactOutput, FilteredSources, Graph, Project, ProjectCompileOutput, Sources, }; +use foundry_compilers_core::error::Result; use rayon::prelude::*; -use std::{path::PathBuf, time::Instant}; +use semver::Version; +use std::{collections::HashMap, path::PathBuf, time::Instant}; + +/// A set of different Solc installations with their version and the sources to be compiled +pub(crate) type VersionedSources = HashMap>; + +/// A set of different Solc installations with their version and the sources to be compiled +pub(crate) type VersionedFilteredSources = HashMap>; #[derive(Debug)] pub struct ProjectCompiler<'a, T: ArtifactOutput, C: Compiler> { diff --git a/src/compilers/mod.rs b/crates/project/src/compilers/mod.rs similarity index 96% rename from src/compilers/mod.rs rename to crates/project/src/compilers/mod.rs index 1b195a61..80102eb5 100644 --- a/src/compilers/mod.rs +++ b/crates/project/src/compilers/mod.rs @@ -1,13 +1,13 @@ -use crate::{ - artifacts::{ - output_selection::OutputSelection, Contract, FileToContractsMap, Source, SourceFile, - Sources, - }, - error::Result, +use crate::ProjectPathsConfig; +use core::fmt; +use foundry_compilers_artifacts::{ + error::SourceLocation, + output_selection::OutputSelection, remappings::Remapping, - ProjectPathsConfig, + sources::{Source, Sources}, + Contract, FileToContractsMap, Severity, SourceFile, }; -use core::fmt; +use foundry_compilers_core::error::Result; use semver::{Version, VersionReq}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{ @@ -164,8 +164,8 @@ pub trait CompilationError: { fn is_warning(&self) -> bool; fn is_error(&self) -> bool; - fn source_location(&self) -> Option; - fn severity(&self) -> crate::artifacts::error::Severity; + fn source_location(&self) -> Option; + fn severity(&self) -> Severity; fn error_code(&self) -> Option; } diff --git a/src/compilers/multi.rs b/crates/project/src/compilers/multi.rs similarity index 94% rename from src/compilers/multi.rs rename to crates/project/src/compilers/multi.rs index 18f30b45..622c8aae 100644 --- a/src/compilers/multi.rs +++ b/crates/project/src/compilers/multi.rs @@ -1,21 +1,22 @@ use super::{ - solc::{SolcCompiler, SolcLanguage, SolcVersionedInput}, + solc::{compiler::SOLC_EXTENSIONS, SolcCompiler, SolcVersionedInput}, vyper::{ - error::VyperCompilationError, input::VyperVersionedInput, parser::VyperParsedSource, Vyper, - VyperLanguage, VyperSettings, VYPER_EXTENSIONS, + input::VyperVersionedInput, parser::VyperParsedSource, Vyper, VyperLanguage, + VYPER_EXTENSIONS, }, CompilationError, Compiler, CompilerInput, CompilerOutput, CompilerSettings, CompilerVersion, Language, ParsedSource, }; -use crate::{ - artifacts::{ - output_selection::OutputSelection, Error, Settings as SolcSettings, Source, Sources, - }, - error::{Result, SolcError}, +use crate::resolver::parse::SolData; +use foundry_compilers_artifacts::{ + error::SourceLocation, + output_selection::OutputSelection, remappings::Remapping, - resolver::parse::SolData, - SOLC_EXTENSIONS, + sources::{Source, Sources}, + vyper::{error::VyperCompilationError, VyperSettings}, + Error, Settings as SolcSettings, Severity, SolcLanguage, }; +use foundry_compilers_core::error::{Result, SolcError}; use semver::Version; use serde::{Deserialize, Serialize}; use std::{ @@ -353,14 +354,14 @@ impl CompilationError for MultiCompilerError { } } - fn source_location(&self) -> Option { + fn source_location(&self) -> Option { match self { Self::Solc(error) => error.source_location(), Self::Vyper(error) => error.source_location(), } } - fn severity(&self) -> crate::artifacts::error::Severity { + fn severity(&self) -> Severity { match self { Self::Solc(error) => error.severity(), Self::Vyper(error) => error.severity(), diff --git a/src/compile/mod.rs b/crates/project/src/compilers/solc/compiler.rs similarity index 92% rename from src/compile/mod.rs rename to crates/project/src/compilers/solc/compiler.rs index 37776e0f..20ef5085 100644 --- a/src/compile/mod.rs +++ b/crates/project/src/compilers/solc/compiler.rs @@ -1,11 +1,10 @@ -use crate::{ - artifacts::Source, +use crate::resolver::parse::SolData; +use foundry_compilers_artifacts::{sources::Source, CompilerOutput, SolcInput}; +use foundry_compilers_core::{ error::{Result, SolcError}, - resolver::parse::SolData, - utils, CompilerOutput, SolcInput, + utils::{self, SUPPORTS_BASE_PATH, SUPPORTS_INCLUDE_PATH}, }; use itertools::Itertools; -use once_cell::sync::Lazy; use semver::{Version, VersionReq}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{ @@ -15,63 +14,12 @@ use std::{ str::FromStr, }; -pub mod many; - -pub mod output; -pub use output::{contracts, info, sources}; - -pub mod project; - /// The name of the `solc` binary on the system pub const SOLC: &str = "solc"; /// Extensions acceptable by solc compiler. pub const SOLC_EXTENSIONS: &[&str] = &["sol", "yul"]; -/// Support for configuring the EVM version -/// -pub const BYZANTIUM_SOLC: Version = Version::new(0, 4, 21); - -/// Bug fix for configuring the EVM version with Constantinople -/// -pub const CONSTANTINOPLE_SOLC: Version = Version::new(0, 4, 22); - -/// Petersburg support -/// -pub const PETERSBURG_SOLC: Version = Version::new(0, 5, 5); - -/// Istanbul support -/// -pub const ISTANBUL_SOLC: Version = Version::new(0, 5, 14); - -/// Berlin support -/// -pub const BERLIN_SOLC: Version = Version::new(0, 8, 5); - -/// London support -/// -pub const LONDON_SOLC: Version = Version::new(0, 8, 7); - -/// Paris support -/// -pub const PARIS_SOLC: Version = Version::new(0, 8, 18); - -/// Shanghai support -/// -pub const SHANGHAI_SOLC: Version = Version::new(0, 8, 20); - -/// Cancun support -/// -pub const CANCUN_SOLC: Version = Version::new(0, 8, 24); - -// `--base-path` was introduced in 0.6.9 -pub static SUPPORTS_BASE_PATH: Lazy = - Lazy::new(|| VersionReq::parse(">=0.6.9").unwrap()); - -// `--include-path` was introduced in 0.8.8 -pub static SUPPORTS_INCLUDE_PATH: Lazy = - Lazy::new(|| VersionReq::parse(">=0.8.8").unwrap()); - /// take the lock in tests, we use this to enforce that /// a test does not run while a compiler version is being installed /// diff --git a/src/compilers/solc.rs b/crates/project/src/compilers/solc/mod.rs similarity index 89% rename from src/compilers/solc.rs rename to crates/project/src/compilers/solc/mod.rs index da969591..20d7fced 100644 --- a/src/compilers/solc.rs +++ b/crates/project/src/compilers/solc/mod.rs @@ -1,27 +1,26 @@ -use itertools::Itertools; - use super::{ CompilationError, Compiler, CompilerInput, CompilerOutput, CompilerSettings, CompilerVersion, Language, ParsedSource, }; -use crate::{ - artifacts::{ - output_selection::OutputSelection, Error, Settings as SolcSettings, SolcInput, Source, - Sources, - }, - error::Result, +use crate::resolver::parse::SolData; +use compiler::{Solc, SOLC_EXTENSIONS}; +use foundry_compilers_artifacts::{ + error::SourceLocation, + output_selection::OutputSelection, remappings::Remapping, - resolver::parse::SolData, - Solc, SOLC_EXTENSIONS, + sources::{Source, Sources}, + Error, Settings as SolcSettings, Severity, SolcInput, SolcLanguage, }; +use foundry_compilers_core::error::Result; +use itertools::Itertools; use semver::Version; use serde::{Deserialize, Serialize}; use std::{ borrow::Cow, collections::BTreeSet, - fmt, path::{Path, PathBuf}, }; +pub mod compiler; #[derive(Debug, Clone)] #[cfg_attr(feature = "svm-solc", derive(Default))] @@ -33,30 +32,13 @@ pub enum SolcCompiler { Specific(Solc), } -/// Languages supported by the Solc compiler. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[non_exhaustive] -pub enum SolcLanguage { - Solidity, - Yul, -} - impl Language for SolcLanguage { const FILE_EXTENSIONS: &'static [&'static str] = SOLC_EXTENSIONS; } -impl fmt::Display for SolcLanguage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Solidity => write!(f, "Solidity"), - Self::Yul => write!(f, "Yul"), - } - } -} - impl Compiler for SolcCompiler { type Input = SolcVersionedInput; - type CompilationError = crate::artifacts::Error; + type CompilationError = Error; type ParsedSource = SolData; type Settings = SolcSettings; type Language = SolcLanguage; @@ -269,11 +251,11 @@ impl CompilationError for Error { self.severity.is_error() } - fn source_location(&self) -> Option { + fn source_location(&self) -> Option { self.source_location.clone() } - fn severity(&self) -> crate::artifacts::error::Severity { + fn severity(&self) -> Severity { self.severity } diff --git a/crates/project/src/compilers/vyper/error.rs b/crates/project/src/compilers/vyper/error.rs new file mode 100644 index 00000000..5b4c385a --- /dev/null +++ b/crates/project/src/compilers/vyper/error.rs @@ -0,0 +1,26 @@ +use crate::compilers::CompilationError; +use foundry_compilers_artifacts::{ + error::SourceLocation, vyper::error::VyperCompilationError, Severity, +}; + +impl CompilationError for VyperCompilationError { + fn is_warning(&self) -> bool { + self.severity.is_warning() + } + + fn is_error(&self) -> bool { + self.severity.is_error() + } + + fn source_location(&self) -> Option { + None + } + + fn severity(&self) -> Severity { + self.severity + } + + fn error_code(&self) -> Option { + None + } +} diff --git a/crates/project/src/compilers/vyper/input.rs b/crates/project/src/compilers/vyper/input.rs new file mode 100644 index 00000000..43f4898a --- /dev/null +++ b/crates/project/src/compilers/vyper/input.rs @@ -0,0 +1,55 @@ +use super::VyperLanguage; +use crate::compilers::CompilerInput; +use foundry_compilers_artifacts::{ + sources::{Source, Sources}, + vyper::{input::VyperInput, VyperSettings}, +}; +use semver::Version; +use serde::Serialize; +use std::{borrow::Cow, path::Path}; + +#[derive(Debug, Clone, Serialize)] +pub struct VyperVersionedInput { + #[serde(flatten)] + pub input: VyperInput, + #[serde(skip)] + pub version: Version, +} + +impl CompilerInput for VyperVersionedInput { + type Settings = VyperSettings; + type Language = VyperLanguage; + + fn build( + sources: Sources, + settings: Self::Settings, + _language: Self::Language, + version: Version, + ) -> Self { + Self { input: VyperInput::new(sources, settings), version } + } + + fn compiler_name(&self) -> Cow<'static, str> { + "Vyper".into() + } + + fn strip_prefix(&mut self, base: &Path) { + self.input.strip_prefix(base); + } + + fn language(&self) -> Self::Language { + VyperLanguage + } + + fn version(&self) -> &Version { + &self.version + } + + fn sources(&self) -> impl Iterator { + self.input + .sources + .iter() + .chain(self.input.interfaces.iter()) + .map(|(path, source)| (path.as_path(), source)) + } +} diff --git a/src/compilers/vyper/mod.rs b/crates/project/src/compilers/vyper/mod.rs similarity index 95% rename from src/compilers/vyper/mod.rs rename to crates/project/src/compilers/vyper/mod.rs index 75524063..38c69586 100644 --- a/src/compilers/vyper/mod.rs +++ b/crates/project/src/compilers/vyper/mod.rs @@ -1,15 +1,11 @@ -use self::{ - error::VyperCompilationError, - input::{VyperInput, VyperVersionedInput}, - parser::VyperParsedSource, -}; +use self::{input::VyperVersionedInput, parser::VyperParsedSource}; use super::{Compiler, CompilerOutput, Language}; -use crate::{ - artifacts::Source, - error::{Result, SolcError}, -}; use core::fmt; -use output::VyperOutput; +use foundry_compilers_artifacts::{ + sources::Source, + vyper::{error::VyperCompilationError, input::VyperInput, output::VyperOutput, VyperSettings}, +}; +use foundry_compilers_core::error::{Result, SolcError}; use semver::Version; use serde::{de::DeserializeOwned, Serialize}; use std::{ @@ -23,7 +19,6 @@ pub mod input; pub mod output; pub mod parser; pub mod settings; -pub use settings::VyperSettings; /// File extensions that are recognized as Vyper source files. pub const VYPER_EXTENSIONS: &[&str] = &["vy", "vyi"]; diff --git a/crates/project/src/compilers/vyper/output.rs b/crates/project/src/compilers/vyper/output.rs new file mode 100644 index 00000000..b2477fcb --- /dev/null +++ b/crates/project/src/compilers/vyper/output.rs @@ -0,0 +1,15 @@ +use foundry_compilers_artifacts::vyper::{error::VyperCompilationError, output::VyperOutput}; + +impl From for super::CompilerOutput { + fn from(output: VyperOutput) -> Self { + super::CompilerOutput { + errors: output.errors, + contracts: output + .contracts + .into_iter() + .map(|(k, v)| (k, v.into_iter().map(|(k, v)| (k, v.into())).collect())) + .collect(), + sources: output.sources.into_iter().map(|(k, v)| (k, v.into())).collect(), + } + } +} diff --git a/src/compilers/vyper/parser.rs b/crates/project/src/compilers/vyper/parser.rs similarity index 98% rename from src/compilers/vyper/parser.rs rename to crates/project/src/compilers/vyper/parser.rs index 86d456d8..5d639662 100644 --- a/src/compilers/vyper/parser.rs +++ b/crates/project/src/compilers/vyper/parser.rs @@ -1,10 +1,12 @@ +use super::VyperLanguage; use crate::{ compilers::{vyper::VYPER_EXTENSIONS, ParsedSource}, - error::{Result, SolcError}, - resolver::parse::capture_outer_and_inner, - utils::RE_VYPER_VERSION, ProjectPathsConfig, }; +use foundry_compilers_core::{ + error::{Result, SolcError}, + utils::{capture_outer_and_inner, RE_VYPER_VERSION}, +}; use semver::VersionReq; use std::path::{Path, PathBuf}; use winnow::{ @@ -14,8 +16,6 @@ use winnow::{ PResult, Parser, }; -use super::VyperLanguage; - #[derive(Debug, Clone, PartialEq)] pub struct VyperImport { pub level: usize, diff --git a/crates/project/src/compilers/vyper/settings.rs b/crates/project/src/compilers/vyper/settings.rs new file mode 100644 index 00000000..de806907 --- /dev/null +++ b/crates/project/src/compilers/vyper/settings.rs @@ -0,0 +1,16 @@ +use crate::compilers::CompilerSettings; +use foundry_compilers_artifacts::{output_selection::OutputSelection, vyper::VyperSettings}; + +impl CompilerSettings for VyperSettings { + fn update_output_selection(&mut self, f: impl FnOnce(&mut OutputSelection)) { + f(&mut self.output_selection) + } + + fn can_use_cached(&self, other: &Self) -> bool { + let Self { evm_version, optimize, bytecode_metadata, output_selection } = self; + evm_version == &other.evm_version + && optimize == &other.optimize + && bytecode_metadata == &other.bytecode_metadata + && output_selection.is_subset_of(&other.output_selection) + } +} diff --git a/src/config.rs b/crates/project/src/config.rs similarity index 99% rename from src/config.rs rename to crates/project/src/config.rs index 4b0b47ee..a92a0886 100644 --- a/src/config.rs +++ b/crates/project/src/config.rs @@ -1,12 +1,19 @@ use crate::{ - artifacts::{output_selection::ContractOutputSelection, Settings}, cache::SOLIDITY_FILES_CACHE_FILENAME, - compilers::{multi::MultiCompilerLanguage, solc::SolcLanguage, Language}, - error::{Result, SolcError, SolcIoError}, + compilers::{multi::MultiCompilerLanguage, Language}, flatten::{collect_ordered_deps, combine_version_pragmas}, + resolver::{parse::SolData, SolImportAlias}, + Graph, +}; +use foundry_compilers_artifacts::{ + output_selection::ContractOutputSelection, remappings::Remapping, - resolver::{parse::SolData, Graph, SolImportAlias}, - utils, Source, Sources, + sources::{Source, Sources}, + Settings, SolcLanguage, +}; +use foundry_compilers_core::{ + error::{Result, SolcError, SolcIoError}, + utils, }; use serde::{Deserialize, Serialize}; use std::{ diff --git a/src/filter.rs b/crates/project/src/filter.rs similarity index 99% rename from src/filter.rs rename to crates/project/src/filter.rs index 6117e71b..95b2c669 100644 --- a/src/filter.rs +++ b/crates/project/src/filter.rs @@ -1,11 +1,11 @@ //! Types to apply filter to input types use crate::{ - artifacts::output_selection::OutputSelection, compilers::{multi::MultiCompilerParsedSource, CompilerSettings, ParsedSource}, resolver::{parse::SolData, GraphEdges}, Source, Sources, }; +use foundry_compilers_artifacts::output_selection::OutputSelection; use std::{ collections::{BTreeMap, HashSet}, fmt::{self, Formatter}, diff --git a/src/flatten.rs b/crates/project/src/flatten.rs similarity index 98% rename from src/flatten.rs rename to crates/project/src/flatten.rs index d6e3fb35..02bffa11 100644 --- a/src/flatten.rs +++ b/crates/project/src/flatten.rs @@ -1,15 +1,17 @@ use crate::{ - artifacts::{ - ast::SourceLocation, - visitor::{Visitor, Walk}, - ContractDefinitionPart, ExternalInlineAssemblyReference, Identifier, IdentifierPath, - MemberAccess, Source, SourceUnit, SourceUnitPart, Sources, - }, compilers::{Compiler, ParsedSource}, - error::SolcError, filter::MaybeSolData, resolver::parse::SolData, - utils, ConfigurableArtifacts, Graph, Project, ProjectCompileOutput, ProjectPathsConfig, Result, + Graph, Project, ProjectCompileOutput, ProjectPathsConfig, +}; +use foundry_compilers_artifacts::{ + ast::{visitor::Visitor, *}, + sources::{Source, Sources}, + ContractDefinitionPart, SourceUnit, SourceUnitPart, +}; +use foundry_compilers_core::{ + error::{Result, SolcError}, + utils, }; use itertools::Itertools; use std::{ @@ -17,6 +19,7 @@ use std::{ hash::Hash, path::{Path, PathBuf}, }; +use visitor::Walk; /// Alternative of `SourceLocation` which includes path of the file. #[derive(Debug, PartialEq, Eq, Hash, Clone)] @@ -178,7 +181,7 @@ impl Flattener { /// into this function. pub fn new( project: &Project, - output: &ProjectCompileOutput, + output: &ProjectCompileOutput, target: &Path, ) -> Result where diff --git a/src/lib.rs b/crates/project/src/lib.rs similarity index 98% rename from src/lib.rs rename to crates/project/src/lib.rs index 9461b6f6..b83d4177 100644 --- a/src/lib.rs +++ b/crates/project/src/lib.rs @@ -7,14 +7,6 @@ #[macro_use] extern crate tracing; -#[macro_use] -pub mod error; - -pub mod artifacts; -pub use artifacts::{CompilerOutput, EvmVersion, SolcInput}; - -pub mod sourcemap; - mod artifact_output; pub use artifact_output::*; @@ -23,12 +15,18 @@ pub mod buildinfo; pub mod cache; pub mod flatten; - -pub mod hh; +use cache::CompilerCache; use compilers::{multi::MultiCompiler, Compiler, CompilerSettings}; -pub use hh::{HardhatArtifact, HardhatArtifacts}; +use foundry_compilers_artifacts::{ + output_selection::OutputSelection, + sources::{Source, Sources}, + Contract, Settings, Severity, SourceFile, StandardJsonCompilerInput, +}; +use foundry_compilers_core::error::{Result, SolcError, SolcIoError}; pub mod resolver; +use output::sources::{VersionedSourceFile, VersionedSourceFiles}; +use project::ProjectCompiler; pub use resolver::Graph; pub mod compilers; @@ -42,8 +40,6 @@ pub use compile::{ mod config; pub use config::{PathStyle, ProjectPaths, ProjectPathsConfig, SolcConfig}; -pub mod remappings; - mod filter; pub use filter::{ FileFilter, FilteredSources, SourceCompilationKind, SparseOutputFilter, TestFileFilter, @@ -51,19 +47,8 @@ pub use filter::{ use solang_parser::pt::SourceUnitPart; pub mod report; - -pub mod utils; - -use crate::{ - artifacts::{Source, SourceFile, Sources, StandardJsonCompilerInput}, - cache::CompilerCache, - error::{SolcError, SolcIoError}, - sources::{VersionedSourceFile, VersionedSourceFiles}, -}; -use artifacts::{contract::Contract, output_selection::OutputSelection, Settings, Severity}; use compile::output::contracts::VersionedContracts; use derivative::Derivative; -use error::Result; use semver::Version; use std::{ collections::{BTreeMap, HashMap, HashSet}, @@ -320,7 +305,7 @@ impl Project { { let sources = Source::read_all(files)?; - project::ProjectCompiler::with_sources(self, sources)?.compile() + ProjectCompiler::with_sources(self, sources)?.compile() } /// Removes the project's artifacts and cache file diff --git a/src/project_util/mock.rs b/crates/project/src/project_util/mock.rs similarity index 100% rename from src/project_util/mock.rs rename to crates/project/src/project_util/mock.rs diff --git a/src/project_util/mod.rs b/crates/project/src/project_util/mod.rs similarity index 100% rename from src/project_util/mod.rs rename to crates/project/src/project_util/mod.rs diff --git a/src/report/compiler.rs b/crates/project/src/report/compiler.rs similarity index 99% rename from src/report/compiler.rs rename to crates/project/src/report/compiler.rs index 7dd5d7b6..c43050b4 100644 --- a/src/report/compiler.rs +++ b/crates/project/src/report/compiler.rs @@ -5,7 +5,7 @@ //! to get this info when debugging an issue. Most convenient way to look at these object is as a //! separate json file -use crate::{CompilerOutput, SolcInput}; +use foundry_compilers_artifacts::{CompilerOutput, SolcInput}; use semver::Version; use std::{env, path::PathBuf, str::FromStr}; diff --git a/src/report/mod.rs b/crates/project/src/report/mod.rs similarity index 99% rename from src/report/mod.rs rename to crates/project/src/report/mod.rs index fb6cc740..4287d9f7 100644 --- a/src/report/mod.rs +++ b/crates/project/src/report/mod.rs @@ -14,7 +14,7 @@ // -use crate::remappings::Remapping; +use foundry_compilers_artifacts::remappings::Remapping; use semver::Version; use std::{ any::{Any, TypeId}, diff --git a/src/resolver/mod.rs b/crates/project/src/resolver/mod.rs similarity index 99% rename from src/resolver/mod.rs rename to crates/project/src/resolver/mod.rs index eeee04a7..57e43e9a 100644 --- a/src/resolver/mod.rs +++ b/crates/project/src/resolver/mod.rs @@ -46,12 +46,16 @@ //! which is defined on a per source file basis. use crate::{ - artifacts::VersionedSources, compilers::{Compiler, CompilerVersion, Language, ParsedSource}, - error::Result, - utils, ProjectPathsConfig, SolcError, Source, Sources, + project::VersionedSources, + ProjectPathsConfig, }; use core::fmt; +use foundry_compilers_artifacts::sources::{Source, Sources}; +use foundry_compilers_core::{ + error::{Result, SolcError}, + utils::{self, find_case_sensitive_existing_file}, +}; use parse::SolData; use rayon::prelude::*; use semver::{Version, VersionReq}; @@ -64,7 +68,6 @@ use std::{ pub mod parse; mod tree; -use crate::utils::find_case_sensitive_existing_file; pub use parse::SolImportAlias; pub use tree::{print, Charset, TreeOptions}; diff --git a/src/resolver/parse.rs b/crates/project/src/resolver/parse.rs similarity index 90% rename from src/resolver/parse.rs rename to crates/project/src/resolver/parse.rs index 29880375..f1cee29a 100644 --- a/src/resolver/parse.rs +++ b/crates/project/src/resolver/parse.rs @@ -1,4 +1,4 @@ -use crate::utils; +use foundry_compilers_core::utils; use semver::VersionReq; use solang_parser::pt::{ ContractPart, ContractTy, FunctionAttribute, FunctionDefinition, Import, ImportPath, Loc, @@ -101,17 +101,24 @@ impl SolData { file.display(), err ); - version = - capture_outer_and_inner(content, &utils::RE_SOL_PRAGMA_VERSION, &["version"]) - .first() - .map(|(cap, name)| SolDataUnit::new(name.as_str().to_owned(), cap.range())); + version = utils::capture_outer_and_inner( + content, + &utils::RE_SOL_PRAGMA_VERSION, + &["version"], + ) + .first() + .map(|(cap, name)| SolDataUnit::new(name.as_str().to_owned(), cap.range())); imports = capture_imports(content); } }; let license = content.lines().next().and_then(|line| { - capture_outer_and_inner(line, &utils::RE_SOL_SDPX_LICENSE_IDENTIFIER, &["license"]) - .first() - .map(|(cap, l)| SolDataUnit::new(l.as_str().to_owned(), cap.range())) + utils::capture_outer_and_inner( + line, + &utils::RE_SOL_SDPX_LICENSE_IDENTIFIER, + &["license"], + ) + .first() + .map(|(cap, l)| SolDataUnit::new(l.as_str().to_owned(), cap.range())) }); let version_req = version.as_ref().and_then(|v| Self::parse_version_req(v.data()).ok()); @@ -240,26 +247,6 @@ impl SolDataUnit { } } -/// Given the regex and the target string, find all occurrences -/// of named groups within the string. This method returns -/// the tuple of matches `(a, b)` where `a` is the match for the -/// entire regex and `b` is the match for the first named group. -/// -/// NOTE: This method will return the match for the first named -/// group, so the order of passed named groups matters. -pub fn capture_outer_and_inner<'a>( - content: &'a str, - regex: ®ex::Regex, - names: &[&str], -) -> Vec<(regex::Match<'a>, regex::Match<'a>)> { - regex - .captures_iter(content) - .filter_map(|cap| { - let cap_match = names.iter().find_map(|name| cap.name(name)); - cap_match.and_then(|m| cap.get(0).map(|outer| (outer.to_owned(), m))) - }) - .collect() -} /// Capture the import statement information together with aliases pub fn capture_imports(content: &str) -> Vec> { let mut imports = vec![]; diff --git a/src/resolver/tree.rs b/crates/project/src/resolver/tree.rs similarity index 100% rename from src/resolver/tree.rs rename to crates/project/src/resolver/tree.rs From 4b800527824a67ece934a23a7192e67465946688 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:05:30 +0300 Subject: [PATCH 02/22] fix tests --- Cargo.toml | 11 +- benches/compile_many.rs | 2 +- crates/artifacts/Cargo.toml | 10 + crates/artifacts/LICENSE-APACHE | 176 ++++++++++++++++++ crates/artifacts/LICENSE-MIT | 19 ++ crates/artifacts/src/ast/lowfidelity.rs | 2 +- crates/artifacts/src/ast/mod.rs | 2 +- crates/artifacts/src/bytecode.rs | 2 +- crates/artifacts/src/configurable.rs | 110 +++++++++++ crates/artifacts/src/contract.rs | 13 -- crates/artifacts/src/lib.rs | 68 +------ crates/artifacts/src/remappings.rs | 61 +----- crates/artifacts/src/sourcemap.rs | 4 +- crates/artifacts/src/vyper/output.rs | 2 +- crates/core/Cargo.toml | 16 +- crates/core/LICENSE-APACHE | 176 ++++++++++++++++++ crates/core/LICENSE-MIT | 19 ++ crates/core/src/error.rs | 2 + crates/core/src/lib.rs | 2 + crates/core/src/utils.rs | 27 ++- crates/project/Cargo.toml | 60 +++++- .../src/artifact_output/configurable.rs | 111 +---------- crates/project/src/artifact_output/hh.rs | 2 +- crates/project/src/artifact_output/mod.rs | 8 + crates/project/src/buildinfo.rs | 12 +- crates/project/src/compile/many.rs | 2 +- crates/project/src/compile/project.rs | 16 +- crates/project/src/compilers/mod.rs | 1 + crates/project/src/compilers/multi.rs | 2 +- crates/project/src/compilers/solc/compiler.rs | 47 ++--- crates/project/src/compilers/solc/mod.rs | 65 ++++++- crates/project/src/compilers/vyper/mod.rs | 5 +- .../project/src/compilers/vyper/settings.rs | 3 +- crates/project/src/config.rs | 16 +- crates/project/src/lib.rs | 83 +++++++-- crates/project/src/project_util/mock.rs | 15 +- crates/project/src/project_util/mod.rs | 19 +- crates/project/src/resolver/mod.rs | 8 +- {tests => crates/project/tests}/mocked.rs | 4 +- {tests => crates/project/tests}/project.rs | 100 +++++----- 40 files changed, 920 insertions(+), 383 deletions(-) create mode 100644 crates/artifacts/LICENSE-APACHE create mode 100644 crates/artifacts/LICENSE-MIT create mode 100644 crates/artifacts/src/configurable.rs create mode 100644 crates/core/LICENSE-APACHE create mode 100644 crates/core/LICENSE-MIT rename {tests => crates/project/tests}/mocked.rs (98%) rename {tests => crates/project/tests}/project.rs (96%) diff --git a/Cargo.toml b/Cargo.toml index 0d2f34cc..7ba4dacc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ members = ["crates/*"] resolver = "2" [workspace.package] -name = "foundry-compilers" authors = ["Foundry Maintainers"] version = "0.7.0" rust-version = "1.65" @@ -31,4 +30,12 @@ thiserror = "1" regex = "1.10" path-slash = "0.2" md-5 = "0.10" -yansi = "1.0.1" \ No newline at end of file +yansi = "1.0.1" +once_cell = "1.19" +svm = { package = "svm-rs", version = "0.5", default-features = false } +solang-parser = { version = "=0.3.3", default-features = false } +pretty_assertions = "1" + +# async +futures-util = "0.3" +tokio = { version = "1.35", features = ["rt-multi-thread"] } \ No newline at end of file diff --git a/benches/compile_many.rs b/benches/compile_many.rs index ada73a62..344f4a20 100644 --- a/benches/compile_many.rs +++ b/benches/compile_many.rs @@ -38,7 +38,7 @@ fn compile_many_benchmark(c: &mut Criterion) { fn load_compiler_inputs() -> Vec { let mut inputs = Vec::new(); - for file in std::fs::read_dir(Path::new(&env!("CARGO_MANIFEST_DIR")).join("test-data/in")) + for file in std::fs::read_dir(Path::new(&env!("CARGO_MANIFEST_DIR")).join("../../test-data/in")) .unwrap() .take(5) { diff --git a/crates/artifacts/Cargo.toml b/crates/artifacts/Cargo.toml index 3d5107ce..82a074a4 100644 --- a/crates/artifacts/Cargo.toml +++ b/crates/artifacts/Cargo.toml @@ -31,5 +31,15 @@ rayon.workspace = true thiserror.workspace = true md-5.workspace = true yansi.workspace = true +futures-util = { workspace = true, optional = true} +tokio = { workspace = true, optional = true } walkdir = "2.4" + +[dev_dependencies] +serde_path_to_error = "0.1" +pretty_assertions.workspace = true +foundry-compilers-core = { workspace = true, features = ["test-utils"] } + +[features] +async = ["dep:tokio", "futures-util", "tokio/fs"] \ No newline at end of file diff --git a/crates/artifacts/LICENSE-APACHE b/crates/artifacts/LICENSE-APACHE new file mode 100644 index 00000000..d9a10c0d --- /dev/null +++ b/crates/artifacts/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/crates/artifacts/LICENSE-MIT b/crates/artifacts/LICENSE-MIT new file mode 100644 index 00000000..cb2a219b --- /dev/null +++ b/crates/artifacts/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2020 Georgios Konstantopoulos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/artifacts/src/ast/lowfidelity.rs b/crates/artifacts/src/ast/lowfidelity.rs index 2f701a8a..db9d7f57 100644 --- a/crates/artifacts/src/ast/lowfidelity.rs +++ b/crates/artifacts/src/ast/lowfidelity.rs @@ -213,7 +213,7 @@ mod tests { #[test] fn can_parse_ast() { - let ast = include_str!("../../../test-data/ast/ast-erc4626.json"); + let ast = include_str!("../../../../test-data/ast/ast-erc4626.json"); let _ast: Ast = serde_json::from_str(ast).unwrap(); } } diff --git a/crates/artifacts/src/ast/mod.rs b/crates/artifacts/src/ast/mod.rs index 1ab6bb49..5c280ff5 100644 --- a/crates/artifacts/src/ast/mod.rs +++ b/crates/artifacts/src/ast/mod.rs @@ -1093,7 +1093,7 @@ mod tests { #[test] fn can_parse_ast() { - fs::read_dir(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data").join("ast")) + fs::read_dir(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data").join("ast")) .unwrap() .for_each(|path| { let path = path.unwrap().path(); diff --git a/crates/artifacts/src/bytecode.rs b/crates/artifacts/src/bytecode.rs index 0f1d43d0..eb1be30d 100644 --- a/crates/artifacts/src/bytecode.rs +++ b/crates/artifacts/src/bytecode.rs @@ -499,7 +499,7 @@ impl From for DeployedBytecode { #[cfg(test)] mod tests { - use crate::{artifacts::ContractBytecode, ConfigurableContractArtifact}; + use crate::{ConfigurableContractArtifact, ContractBytecode}; #[test] fn test_empty_bytecode() { diff --git a/crates/artifacts/src/configurable.rs b/crates/artifacts/src/configurable.rs new file mode 100644 index 00000000..95ccb830 --- /dev/null +++ b/crates/artifacts/src/configurable.rs @@ -0,0 +1,110 @@ +use std::{borrow::Cow, collections::BTreeMap}; + +use crate::{ + Ast, CompactBytecode, CompactContract, CompactContractBytecode, CompactContractBytecodeCow, + CompactDeployedBytecode, DevDoc, Ewasm, FunctionDebugData, GasEstimates, GeneratedSource, + Metadata, Offsets, SourceFile, StorageLayout, UserDoc, +}; +use alloy_json_abi::JsonAbi; +use serde::{Deserialize, Serialize}; + +/// Represents the `Artifact` that `ConfigurableArtifacts` emits. +/// +/// This is essentially a superset of [`CompactContractBytecode`]. +#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct ConfigurableContractArtifact { + /// The Ethereum Contract ABI. If empty, it is represented as an empty + /// array. See + pub abi: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub bytecode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub deployed_bytecode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub assembly: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub opcodes: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub method_identifiers: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub generated_sources: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub function_debug_data: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub gas_estimates: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub raw_metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub metadata: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub storage_layout: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub userdoc: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub devdoc: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ir: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ir_optimized: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ewasm: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ast: Option, + /// The identifier of the source file + #[serde(default, skip_serializing_if = "Option::is_none")] + pub id: Option, +} + +impl ConfigurableContractArtifact { + /// Returns the inner element that contains the core bytecode related information + pub fn into_contract_bytecode(self) -> CompactContractBytecode { + self.into() + } + + /// Looks for all link references in deployment and runtime bytecodes + pub fn all_link_references(&self) -> BTreeMap>> { + let mut links = BTreeMap::new(); + if let Some(bcode) = &self.bytecode { + links.extend(bcode.link_references.clone()); + } + + if let Some(d_bcode) = &self.deployed_bytecode { + if let Some(bcode) = &d_bcode.bytecode { + links.extend(bcode.link_references.clone()); + } + } + links + } + + /// Returns the source file of this artifact's contract + pub fn source_file(&self) -> Option { + self.id.map(|id| SourceFile { id, ast: self.ast.clone() }) + } +} + +impl From for CompactContractBytecode { + fn from(artifact: ConfigurableContractArtifact) -> Self { + CompactContractBytecode { + abi: artifact.abi.map(Into::into), + bytecode: artifact.bytecode, + deployed_bytecode: artifact.deployed_bytecode, + } + } +} + +impl From for CompactContract { + fn from(artifact: ConfigurableContractArtifact) -> Self { + CompactContractBytecode::from(artifact).into() + } +} + +impl<'a> From<&'a ConfigurableContractArtifact> for CompactContractBytecodeCow<'a> { + fn from(artifact: &'a ConfigurableContractArtifact) -> Self { + CompactContractBytecodeCow { + abi: artifact.abi.as_ref().map(Cow::Borrowed), + bytecode: artifact.bytecode.as_ref().map(Cow::Borrowed), + deployed_bytecode: artifact.deployed_bytecode.as_ref().map(Cow::Borrowed), + } + } +} diff --git a/crates/artifacts/src/contract.rs b/crates/artifacts/src/contract.rs index 35f75d4e..f0cfb68e 100644 --- a/crates/artifacts/src/contract.rs +++ b/crates/artifacts/src/contract.rs @@ -569,16 +569,3 @@ impl<'a> From<&'a Contract> for CompactContractRef<'a> { Self { abi: c.abi.as_ref(), bin, bin_runtime } } } - -#[cfg(test)] -mod tests { - use super::*; - - fn assert_artifact() {} - - #[test] - fn test() { - assert_artifact::(); - assert_artifact::>(); - } -} diff --git a/crates/artifacts/src/lib.rs b/crates/artifacts/src/lib.rs index 6b015014..82b9ab84 100644 --- a/crates/artifacts/src/lib.rs +++ b/crates/artifacts/src/lib.rs @@ -1,5 +1,6 @@ //! Solc artifact types. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] #![allow(ambiguous_glob_reexports)] #[macro_use] @@ -25,7 +26,9 @@ pub mod bytecode; pub use bytecode::*; pub mod contract; pub use contract::*; +pub mod configurable; pub mod hh; +pub use configurable::*; pub mod output_selection; pub mod serde_helpers; pub mod sourcemap; @@ -1890,58 +1893,8 @@ impl SourceFiles { #[cfg(test)] mod tests { use super::*; - use crate::{ - buildinfo::RawBuildInfo, - compilers::{ - solc::{SolcCompiler, SolcVersionedInput}, - CompilerInput, - }, - AggregatedCompilerOutput, - }; use alloy_primitives::Address; - - #[test] - fn can_parse_declaration_error() { - let s = r#"{ - "errors": [ - { - "component": "general", - "errorCode": "7576", - "formattedMessage": "DeclarationError: Undeclared identifier. Did you mean \"revert\"?\n --> /Users/src/utils/UpgradeProxy.sol:35:17:\n |\n35 | refert(\"Transparent ERC1967 proxies do not have upgradeable implementations\");\n | ^^^^^^\n\n", - "message": "Undeclared identifier. Did you mean \"revert\"?", - "severity": "error", - "sourceLocation": { - "end": 1623, - "file": "/Users/src/utils/UpgradeProxy.sol", - "start": 1617 - }, - "type": "DeclarationError" - } - ], - "sources": { } -}"#; - - let out: CompilerOutput = serde_json::from_str(s).unwrap(); - assert_eq!(out.errors.len(), 1); - - let out_converted = crate::compilers::CompilerOutput { - errors: out.errors, - contracts: Default::default(), - sources: Default::default(), - }; - - let v: Version = "0.8.12".parse().unwrap(); - let input = SolcVersionedInput::build( - Default::default(), - Default::default(), - SolcLanguage::Solidity, - v.clone(), - ); - let build_info = RawBuildInfo::new(&input, &out_converted, true).unwrap(); - let mut aggregated = AggregatedCompilerOutput::::default(); - aggregated.extend(v, build_info, out_converted); - assert!(!aggregated.is_unchanged()); - } + use std::fs; #[test] fn can_link_bytecode() { @@ -1993,8 +1946,7 @@ mod tests { #[test] fn can_parse_compiler_output() { - let mut dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - dir.push("test-data/out"); + let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/out"); for path in fs::read_dir(dir).unwrap() { let path = path.unwrap().path(); @@ -2007,8 +1959,7 @@ mod tests { #[test] fn can_parse_compiler_input() { - let mut dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - dir.push("test-data/in"); + let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/in"); for path in fs::read_dir(dir).unwrap() { let path = path.unwrap().path(); @@ -2021,8 +1972,7 @@ mod tests { #[test] fn can_parse_standard_json_compiler_input() { - let mut dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - dir.push("test-data/in"); + let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/in"); for path in fs::read_dir(dir).unwrap() { let path = path.unwrap().path(); @@ -2276,7 +2226,7 @@ mod tests { #[test] fn test_lossless_storage_layout() { - let input = include_str!("../../test-data/foundryissue2462.json").trim(); + let input = include_str!("../../../test-data/foundryissue2462.json").trim(); let layout: StorageLayout = serde_json::from_str(input).unwrap(); pretty_assertions::assert_eq!(input, &serde_json::to_string(&layout).unwrap()); } @@ -2285,7 +2235,7 @@ mod tests { #[test] fn can_parse_compiler_output_spells_0_6_12() { let path = - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/0.6.12-with-libs.json"); + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/0.6.12-with-libs.json"); let content = fs::read_to_string(path).unwrap(); let _output: CompilerOutput = serde_json::from_str(&content).unwrap(); } diff --git a/crates/artifacts/src/remappings.rs b/crates/artifacts/src/remappings.rs index 89e4d178..6ebc4dd7 100644 --- a/crates/artifacts/src/remappings.rs +++ b/crates/artifacts/src/remappings.rs @@ -811,8 +811,9 @@ fn last_nested_source_dir(root: &Path, dir: &Path) -> PathBuf { #[cfg(test)] mod tests { + use foundry_compilers_core::utils::{mkdir_or_touch, tempdir, touch}; + use super::*; - use crate::{utils::tempdir, ProjectPathsConfig}; #[test] fn relative_remapping() { @@ -852,29 +853,6 @@ mod tests { matches!(err, RemappingError::EmptyRemappingValue(_)); } - // - fn touch(path: &std::path::Path) -> std::io::Result<()> { - match std::fs::OpenOptions::new().create(true).write(true).truncate(false).open(path) { - Ok(_) => Ok(()), - Err(e) => Err(e), - } - } - - fn mkdir_or_touch(tmp: &std::path::Path, paths: &[&str]) { - for path in paths { - if let Some(parent) = Path::new(path).parent() { - std::fs::create_dir_all(tmp.join(parent)).unwrap(); - } - if path.ends_with(".sol") { - let path = tmp.join(path); - touch(&path).unwrap(); - } else { - let path = tmp.join(path); - std::fs::create_dir_all(path).unwrap(); - } - } - } - // helper function for converting path bufs to remapping strings fn to_str(p: std::path::PathBuf) -> String { format!("{}/", p.display()) @@ -1109,41 +1087,6 @@ mod tests { pretty_assertions::assert_eq!(remappings, expected); } - #[test] - fn can_resolve_oz_remappings() { - let tmp_dir = tempdir("node_modules").unwrap(); - let tmp_dir_node_modules = tmp_dir.path().join("node_modules"); - let paths = [ - "node_modules/@openzeppelin/contracts/interfaces/IERC1155.sol", - "node_modules/@openzeppelin/contracts/finance/VestingWallet.sol", - "node_modules/@openzeppelin/contracts/proxy/Proxy.sol", - "node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol", - ]; - mkdir_or_touch(tmp_dir.path(), &paths[..]); - let remappings = Remapping::find_many(tmp_dir_node_modules); - let mut paths = ProjectPathsConfig::<()>::hardhat(tmp_dir.path()).unwrap(); - paths.remappings = remappings; - - let resolved = paths - .resolve_library_import( - tmp_dir.path(), - Path::new("@openzeppelin/contracts/token/ERC20/IERC20.sol"), - ) - .unwrap(); - assert!(resolved.exists()); - - // adjust remappings - paths.remappings[0].name = "@openzeppelin/".to_string(); - - let resolved = paths - .resolve_library_import( - tmp_dir.path(), - Path::new("@openzeppelin/contracts/token/ERC20/IERC20.sol"), - ) - .unwrap(); - assert!(resolved.exists()); - } - #[test] #[cfg_attr(windows, ignore = "Windows remappings #2347")] fn recursive_remappings() { diff --git a/crates/artifacts/src/sourcemap.rs b/crates/artifacts/src/sourcemap.rs index 50266abc..673de829 100644 --- a/crates/artifacts/src/sourcemap.rs +++ b/crates/artifacts/src/sourcemap.rs @@ -578,7 +578,7 @@ mod tests { #[test] fn can_parse_source_maps() { // all source maps from the compiler output test data - let source_maps = include_str!("../test-data/out-source-maps.txt"); + let source_maps = include_str!("../../../test-data/out-source-maps.txt"); for (line, s) in source_maps.lines().enumerate() { parse(s).unwrap_or_else(|e| panic!("Failed to parse line {line}: {e}")); @@ -587,7 +587,7 @@ mod tests { #[test] fn can_parse_foundry_cheatcodes_sol_maps() { - let s = include_str!("../test-data/cheatcodes.sol-sourcemap.txt"); + let s = include_str!("../../../test-data/cheatcodes.sol-sourcemap.txt"); let mut out = String::new(); let mut parser = Parser::new(s); parser.output = Some(&mut out); diff --git a/crates/artifacts/src/vyper/output.rs b/crates/artifacts/src/vyper/output.rs index 330b43b4..a80a1b8e 100644 --- a/crates/artifacts/src/vyper/output.rs +++ b/crates/artifacts/src/vyper/output.rs @@ -151,7 +151,7 @@ mod tests { fn test_output(artifact_path: &str) { let output = std::fs::read_to_string( - Path::new(env!("CARGO_MANIFEST_DIR")).join("test-data").join(artifact_path), + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../test-data").join(artifact_path), ) .unwrap(); let output: super::VyperOutput = serde_json::from_str(&output).unwrap(); diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 28a48814..a8b24888 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -26,9 +26,23 @@ serde_json.workspace = true regex.workspace = true path-slash.workspace = true alloy-primitives.workspace = true +once_cell.workspace = true +svm = { workspace = true, optional = true } +tokio = { workspace = true, optional = true } walkdir = "2.4" dunce = "1.0" memmap2 = "0.9" cfg-if = "1.0.0" -once_cell = "1.19" \ No newline at end of file + +tempfile = { version = "3.9", optional = true } +fs_extra = { version = "1.3", optional = true } + +[dev_dependencies] +solang-parser.workspace = true + +[features] +project-util = ["dep:tempfile", "dep:fs_extra"] +svm-solc = ["dep:svm", "dep:tokio"] +async = ["dep:tokio"] +test-utils = [] \ No newline at end of file diff --git a/crates/core/LICENSE-APACHE b/crates/core/LICENSE-APACHE new file mode 100644 index 00000000..d9a10c0d --- /dev/null +++ b/crates/core/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/crates/core/LICENSE-MIT b/crates/core/LICENSE-MIT new file mode 100644 index 00000000..cb2a219b --- /dev/null +++ b/crates/core/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2020 Georgios Konstantopoulos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index 8f98e5d5..0e75f5d9 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -8,6 +8,7 @@ use thiserror::Error; pub type Result = std::result::Result; #[allow(unused_macros)] +#[macro_export] macro_rules! format_err { ($($tt:tt)*) => { $crate::error::SolcError::msg(format!($($tt)*)) @@ -15,6 +16,7 @@ macro_rules! format_err { } #[allow(unused_macros)] +#[macro_export] macro_rules! bail { ($($tt:tt)*) => { return Err(format_err!($($tt)*)) }; } diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index caf91b35..2e7e5020 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -1,2 +1,4 @@ +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + pub mod error; pub mod utils; diff --git a/crates/core/src/utils.rs b/crates/core/src/utils.rs index 952f131b..604f7525 100644 --- a/crates/core/src/utils.rs +++ b/crates/core/src/utils.rs @@ -571,7 +571,7 @@ cfg_if! { /// Creates a new named tempdir. #[cfg(any(test, feature = "project-util"))] -pub(crate) fn tempdir(name: &str) -> Result { +pub fn tempdir(name: &str) -> Result { tempfile::Builder::new().prefix(name).tempdir().map_err(|err| SolcIoError::new(err, name)) } @@ -635,6 +635,31 @@ pub fn capture_outer_and_inner<'a>( .collect() } +#[cfg(any(test, feature = "test-utils"))] +// +pub fn touch(path: &std::path::Path) -> std::io::Result<()> { + match std::fs::OpenOptions::new().create(true).write(true).truncate(false).open(path) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } +} + +#[cfg(any(test, feature = "test-utils"))] +pub fn mkdir_or_touch(tmp: &std::path::Path, paths: &[&str]) { + for path in paths { + if let Some(parent) = Path::new(path).parent() { + std::fs::create_dir_all(tmp.join(parent)).unwrap(); + } + if path.ends_with(".sol") { + let path = tmp.join(path); + touch(&path).unwrap(); + } else { + let path: PathBuf = tmp.join(path); + std::fs::create_dir_all(path).unwrap(); + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 008a1987..6f136179 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -32,12 +32,68 @@ md-5.workspace = true thiserror.workspace = true path-slash.workspace = true yansi.workspace = true +solang-parser.workspace = true +once_cell = { workspace = true, optional = true } +futures-util = { workspace = true, optional = true} +tokio = { workspace = true, optional = true } auto_impl = "1" winnow = "0.6" dyn-clone = "1" derivative = "2.2" -solang-parser = { version = "=0.3.3", default-features = false } home = "0.5" dirs = "5.0" -itertools = "0.13" \ No newline at end of file +itertools = "0.13" + +# project-util +tempfile = { version = "3.9", optional = true } +fs_extra = { version = "1.3", optional = true } +rand = { version = "0.8", optional = true } + +# svm +svm = { workspace = true, optional = true } +svm-builds = { package = "svm-rs-builds", version = "0.5", default-features = false, optional = true } +sha2 = { version = "0.10", default-features = false, optional = true } + +[dev_dependencies] +tracing-subscriber = { version = "0.3", default-features = false, features = [ + "env-filter", + "fmt", +] } +pretty_assertions.workspace = true +fd-lock = "4.0.0" +tokio = { version = "1.35", features = ["rt-multi-thread", "macros"] } +reqwest = "0.12" + +[features] +default = ["rustls"] +test-utils = [] + +full = ["async", "svm-solc"] + +# Adds extra `async` methods using `tokio` to some types. +async = [ + "dep:futures-util", + "dep:tokio", + "tokio/fs", + "tokio/process", + "tokio/io-util", + "foundry-compilers-artifacts/async", +] +# Enables `svm` to auto-detect and manage `solc` builds. +svm-solc = ["dep:svm", "dep:svm-builds", "dep:sha2", "foundry-compilers-core/svm-solc", "dep:once_cell"] +# Utilities for creating and testing project workspaces. +project-util = ["dep:tempfile", "dep:fs_extra", "dep:rand", "svm-solc", "foundry-compilers-core/project-util"] + +rustls = ["svm?/rustls"] +openssl = ["svm?/openssl"] + +[[test]] +name = "project" +path = "tests/project.rs" +required-features = ["full", "project-util", "test-utils"] + +[[test]] +name = "mocked" +path = "tests/mocked.rs" +required-features = ["full", "project-util"] \ No newline at end of file diff --git a/crates/project/src/artifact_output/configurable.rs b/crates/project/src/artifact_output/configurable.rs index 6fab70d5..14b69154 100644 --- a/crates/project/src/artifact_output/configurable.rs +++ b/crates/project/src/artifact_output/configurable.rs @@ -16,119 +16,16 @@ use alloy_json_abi::JsonAbi; use alloy_primitives::hex; use foundry_compilers_artifacts::{ bytecode::{CompactBytecode, CompactDeployedBytecode}, - contract::{CompactContract, CompactContractBytecode, Contract}, + contract::Contract, output_selection::{ BytecodeOutputSelection, ContractOutputSelection, DeployedBytecodeOutputSelection, EvmOutputSelection, EwasmOutputSelection, }, - Ast, BytecodeObject, CompactContractBytecodeCow, DevDoc, Evm, Ewasm, FunctionDebugData, - GasEstimates, GeneratedSource, LosslessMetadata, Metadata, Offsets, Settings, StorageLayout, - UserDoc, + BytecodeObject, ConfigurableContractArtifact, Evm, Ewasm, GeneratedSource, LosslessMetadata, + Metadata, Settings, }; use foundry_compilers_core::utils; -use serde::{Deserialize, Serialize}; -use std::{borrow::Cow, collections::BTreeMap, fs, path::Path}; - -/// Represents the `Artifact` that `ConfigurableArtifacts` emits. -/// -/// This is essentially a superset of [`CompactContractBytecode`]. -#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "camelCase")] -pub struct ConfigurableContractArtifact { - /// The Ethereum Contract ABI. If empty, it is represented as an empty - /// array. See - pub abi: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub bytecode: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub deployed_bytecode: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub assembly: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub opcodes: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub method_identifiers: Option>, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub generated_sources: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub function_debug_data: Option>, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub gas_estimates: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub raw_metadata: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub metadata: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub storage_layout: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub userdoc: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub devdoc: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub ir: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub ir_optimized: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub ewasm: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub ast: Option, - /// The identifier of the source file - #[serde(default, skip_serializing_if = "Option::is_none")] - pub id: Option, -} - -impl ConfigurableContractArtifact { - /// Returns the inner element that contains the core bytecode related information - pub fn into_contract_bytecode(self) -> CompactContractBytecode { - self.into() - } - - /// Looks for all link references in deployment and runtime bytecodes - pub fn all_link_references(&self) -> BTreeMap>> { - let mut links = BTreeMap::new(); - if let Some(bcode) = &self.bytecode { - links.extend(bcode.link_references.clone()); - } - - if let Some(d_bcode) = &self.deployed_bytecode { - if let Some(bcode) = &d_bcode.bytecode { - links.extend(bcode.link_references.clone()); - } - } - links - } - - /// Returns the source file of this artifact's contract - pub fn source_file(&self) -> Option { - self.id.map(|id| SourceFile { id, ast: self.ast.clone() }) - } -} - -impl From for CompactContractBytecode { - fn from(artifact: ConfigurableContractArtifact) -> Self { - CompactContractBytecode { - abi: artifact.abi.map(Into::into), - bytecode: artifact.bytecode, - deployed_bytecode: artifact.deployed_bytecode, - } - } -} - -impl From for CompactContract { - fn from(artifact: ConfigurableContractArtifact) -> Self { - CompactContractBytecode::from(artifact).into() - } -} - -impl<'a> From<&'a ConfigurableContractArtifact> for CompactContractBytecodeCow<'a> { - fn from(artifact: &'a ConfigurableContractArtifact) -> Self { - CompactContractBytecodeCow { - abi: artifact.abi.as_ref().map(Cow::Borrowed), - bytecode: artifact.bytecode.as_ref().map(Cow::Borrowed), - deployed_bytecode: artifact.deployed_bytecode.as_ref().map(Cow::Borrowed), - } - } -} +use std::{fs, path::Path}; /// An `Artifact` implementation that can be configured to include additional content and emit /// additional files diff --git a/crates/project/src/artifact_output/hh.rs b/crates/project/src/artifact_output/hh.rs index 1727b0f0..89366e9f 100644 --- a/crates/project/src/artifact_output/hh.rs +++ b/crates/project/src/artifact_output/hh.rs @@ -69,7 +69,7 @@ mod tests { #[test] fn can_parse_hh_artifact() { - let s = include_str!("../test-data/hh-greeter-artifact.json"); + let s = include_str!("../../../../test-data/hh-greeter-artifact.json"); let artifact = serde_json::from_str::(s).unwrap(); let compact = artifact.into_compact_contract(); assert!(compact.abi.is_some()); diff --git a/crates/project/src/artifact_output/mod.rs b/crates/project/src/artifact_output/mod.rs index 6d4b2e76..ecf39158 100644 --- a/crates/project/src/artifact_output/mod.rs +++ b/crates/project/src/artifact_output/mod.rs @@ -1224,4 +1224,12 @@ mod tests { assert_eq!(alternative.to_slash_lossy(), "/Users/carter/dev/goldfinch/mono/packages/protocol/artifacts/utils/BaseMainnetForkingTest.t.sol/BaseMainnetForkingTest.json"); } + + fn assert_artifact() {} + + #[test] + fn test() { + assert_artifact::(); + assert_artifact::>(); + } } diff --git a/crates/project/src/buildinfo.rs b/crates/project/src/buildinfo.rs index a0bd00d4..1fcd7224 100644 --- a/crates/project/src/buildinfo.rs +++ b/crates/project/src/buildinfo.rs @@ -128,15 +128,11 @@ impl RawBuildInfo { #[cfg(test)] mod tests { + use foundry_compilers_artifacts::{sources::Source, Error, SolcLanguage}; + + use crate::compilers::solc::SolcVersionedInput; + use super::*; - use crate::{ - artifacts::Error, - compilers::{ - solc::{SolcLanguage, SolcVersionedInput}, - CompilerOutput, - }, - Source, - }; use std::{collections::BTreeMap, path::PathBuf}; #[test] diff --git a/crates/project/src/compile/many.rs b/crates/project/src/compile/many.rs index 180c19cb..a92b3cda 100644 --- a/crates/project/src/compile/many.rs +++ b/crates/project/src/compile/many.rs @@ -1,7 +1,7 @@ use foundry_compilers_artifacts::{CompilerOutput, SolcInput}; use foundry_compilers_core::error::Result; -use crate::compilers::solc::compiler::Solc; +use crate::compilers::solc::Solc; /// The result of a `solc` process bundled with its `Solc` and `CompilerInput` type CompileElement = (Result, Solc, SolcInput); diff --git a/crates/project/src/compile/project.rs b/crates/project/src/compile/project.rs index 1d8bd048..6ac92fe6 100644 --- a/crates/project/src/compile/project.rs +++ b/crates/project/src/compile/project.rs @@ -625,13 +625,15 @@ fn compile_parallel( mod tests { use std::path::Path; - use super::*; + use foundry_compilers_artifacts::output_selection::ContractOutputSelection; + use crate::{ - artifacts::output_selection::ContractOutputSelection, compilers::multi::MultiCompiler, - project_util::TempProject, ConfigurableArtifacts, MinimalCombinedArtifacts, - ProjectPathsConfig, + compilers::multi::MultiCompiler, project_util::TempProject, ConfigurableArtifacts, + MinimalCombinedArtifacts, ProjectPathsConfig, }; + use super::*; + fn init_tracing() { let _ = tracing_subscriber::fmt() .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) @@ -641,7 +643,7 @@ mod tests { #[test] fn can_preprocess() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/dapp-sample"); let project = Project::builder() .paths(ProjectPathsConfig::dapptools(root).unwrap()) .build(Default::default()) @@ -660,7 +662,7 @@ mod tests { #[test] fn can_detect_cached_files() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/dapp-sample"); let paths = ProjectPathsConfig::builder().sources(root.join("src")).lib(root.join("lib")); let project = TempProject::::new(paths).unwrap(); @@ -795,7 +797,7 @@ mod tests { #[test] fn extra_output_cached() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/dapp-sample"); let paths = ProjectPathsConfig::builder().sources(root.join("src")).lib(root.join("lib")); let mut project = TempProject::::new(paths.clone()).unwrap(); diff --git a/crates/project/src/compilers/mod.rs b/crates/project/src/compilers/mod.rs index 80102eb5..3ae2ba86 100644 --- a/crates/project/src/compilers/mod.rs +++ b/crates/project/src/compilers/mod.rs @@ -21,6 +21,7 @@ use std::{ pub mod multi; pub mod solc; pub mod vyper; +pub use vyper::*; /// A compiler version is either installed (available locally) or can be downloaded, from the remote /// endpoint diff --git a/crates/project/src/compilers/multi.rs b/crates/project/src/compilers/multi.rs index 622c8aae..8739feb7 100644 --- a/crates/project/src/compilers/multi.rs +++ b/crates/project/src/compilers/multi.rs @@ -1,5 +1,5 @@ use super::{ - solc::{compiler::SOLC_EXTENSIONS, SolcCompiler, SolcVersionedInput}, + solc::{SolcCompiler, SolcVersionedInput, SOLC_EXTENSIONS}, vyper::{ input::VyperVersionedInput, parser::VyperParsedSource, Vyper, VyperLanguage, VYPER_EXTENSIONS, diff --git a/crates/project/src/compilers/solc/compiler.rs b/crates/project/src/compilers/solc/compiler.rs index 20ef5085..6e72b7b3 100644 --- a/crates/project/src/compilers/solc/compiler.rs +++ b/crates/project/src/compilers/solc/compiler.rs @@ -14,9 +14,6 @@ use std::{ str::FromStr, }; -/// The name of the `solc` binary on the system -pub const SOLC: &str = "solc"; - /// Extensions acceptable by solc compiler. pub const SOLC_EXTENSIONS: &[&str] = &["sol", "yul"]; @@ -48,15 +45,17 @@ macro_rules! take_solc_installer_lock { /// we should download. /// The boolean value marks whether there was an error accessing the release list #[cfg(feature = "svm-solc")] -pub static RELEASES: Lazy<(svm::Releases, Vec, bool)> = - Lazy::new(|| match serde_json::from_str::(svm_builds::RELEASE_LIST_JSON) { - Ok(releases) => { - let sorted_versions = releases.clone().into_versions(); - (releases, sorted_versions, true) - } - Err(err) => { - error!("{:?}", err); - Default::default() +pub static RELEASES: once_cell::sync::Lazy<(svm::Releases, Vec, bool)> = + once_cell::sync::Lazy::new(|| { + match serde_json::from_str::(svm_builds::RELEASE_LIST_JSON) { + Ok(releases) => { + let sorted_versions = releases.clone().into_versions(); + (releases, sorted_versions, true) + } + Err(err) => { + error!("{:?}", err); + Default::default() + } } }); @@ -262,7 +261,7 @@ impl Solc { /// Blocking version of `Self::install` #[cfg(feature = "svm-solc")] pub fn blocking_install(version: &Version) -> std::result::Result { - use crate::utils::RuntimeOrHandle; + use foundry_compilers_core::utils::RuntimeOrHandle; #[cfg(test)] crate::take_solc_installer_lock!(_lock); @@ -629,7 +628,7 @@ mod tests { #[test] fn solc_compile_works() { - let input = include_str!("../../test-data/in/compiler-in-1.json"); + let input = include_str!("../../../../../test-data/in/compiler-in-1.json"); let input: SolcInput = serde_json::from_str(input).unwrap(); let out = solc().compile(&input).unwrap(); let other = solc().compile(&serde_json::json!(input)).unwrap(); @@ -638,7 +637,7 @@ mod tests { #[test] fn solc_metadata_works() { - let input = include_str!("../../test-data/in/compiler-in-1.json"); + let input = include_str!("../../../../../test-data/in/compiler-in-1.json"); let mut input: SolcInput = serde_json::from_str(input).unwrap(); input.settings.push_output_selection("metadata"); let out = solc().compile(&input).unwrap(); @@ -649,9 +648,10 @@ mod tests { #[test] fn can_compile_with_remapped_links() { - let input: SolcInput = - serde_json::from_str(include_str!("../../test-data/library-remapping-in.json")) - .unwrap(); + let input: SolcInput = serde_json::from_str(include_str!( + "../../../../../test-data/library-remapping-in.json" + )) + .unwrap(); let out = solc().compile(&input).unwrap(); let (_, mut contracts) = out.split(); let contract = contracts.remove("LinkTest").unwrap(); @@ -661,9 +661,10 @@ mod tests { #[test] fn can_compile_with_remapped_links_temp_dir() { - let input: SolcInput = - serde_json::from_str(include_str!("../../test-data/library-remapping-in-2.json")) - .unwrap(); + let input: SolcInput = serde_json::from_str(include_str!( + "../../../../../test-data/library-remapping-in-2.json" + )) + .unwrap(); let out = solc().compile(&input).unwrap(); let (_, mut contracts) = out.split(); let contract = contracts.remove("LinkTest").unwrap(); @@ -674,7 +675,7 @@ mod tests { #[cfg(feature = "async")] #[tokio::test(flavor = "multi_thread")] async fn async_solc_compile_works() { - let input = include_str!("../../test-data/in/compiler-in-1.json"); + let input = include_str!("../../../../../test-data/in/compiler-in-1.json"); let input: SolcInput = serde_json::from_str(input).unwrap(); let out = solc().async_compile(&input).await.unwrap(); let other = solc().async_compile(&serde_json::json!(input)).await.unwrap(); @@ -684,7 +685,7 @@ mod tests { #[cfg(feature = "async")] #[tokio::test(flavor = "multi_thread")] async fn async_solc_compile_works2() { - let input = include_str!("../../test-data/in/compiler-in-2.json"); + let input = include_str!("../../../../../test-data/in/compiler-in-2.json"); let input: SolcInput = serde_json::from_str(input).unwrap(); let out = solc().async_compile(&input).await.unwrap(); let other = solc().async_compile(&serde_json::json!(input)).await.unwrap(); diff --git a/crates/project/src/compilers/solc/mod.rs b/crates/project/src/compilers/solc/mod.rs index 20d7fced..db6bf7c3 100644 --- a/crates/project/src/compilers/solc/mod.rs +++ b/crates/project/src/compilers/solc/mod.rs @@ -3,13 +3,13 @@ use super::{ Language, ParsedSource, }; use crate::resolver::parse::SolData; -use compiler::{Solc, SOLC_EXTENSIONS}; +pub use foundry_compilers_artifacts::SolcLanguage; use foundry_compilers_artifacts::{ error::SourceLocation, output_selection::OutputSelection, remappings::Remapping, sources::{Source, Sources}, - Error, Settings as SolcSettings, Severity, SolcInput, SolcLanguage, + Error, Settings as SolcSettings, Severity, SolcInput, }; use foundry_compilers_core::error::Result; use itertools::Itertools; @@ -20,7 +20,8 @@ use std::{ collections::BTreeSet, path::{Path, PathBuf}, }; -pub mod compiler; +mod compiler; +pub use compiler::{Solc, SOLC_EXTENSIONS}; #[derive(Debug, Clone)] #[cfg_attr(feature = "svm-solc", derive(Default))] @@ -263,3 +264,61 @@ impl CompilationError for Error { self.error_code } } + +#[cfg(test)] +mod tests { + use foundry_compilers_artifacts::{CompilerOutput, SolcLanguage}; + use semver::Version; + + use crate::{ + buildinfo::RawBuildInfo, + compilers::{ + solc::{SolcCompiler, SolcVersionedInput}, + CompilerInput, + }, + AggregatedCompilerOutput, + }; + + #[test] + fn can_parse_declaration_error() { + let s = r#"{ + "errors": [ + { + "component": "general", + "errorCode": "7576", + "formattedMessage": "DeclarationError: Undeclared identifier. Did you mean \"revert\"?\n --> /Users/src/utils/UpgradeProxy.sol:35:17:\n |\n35 | refert(\"Transparent ERC1967 proxies do not have upgradeable implementations\");\n | ^^^^^^\n\n", + "message": "Undeclared identifier. Did you mean \"revert\"?", + "severity": "error", + "sourceLocation": { + "end": 1623, + "file": "/Users/src/utils/UpgradeProxy.sol", + "start": 1617 + }, + "type": "DeclarationError" + } + ], + "sources": { } +}"#; + + let out: CompilerOutput = serde_json::from_str(s).unwrap(); + assert_eq!(out.errors.len(), 1); + + let out_converted = crate::compilers::CompilerOutput { + errors: out.errors, + contracts: Default::default(), + sources: Default::default(), + }; + + let v: Version = "0.8.12".parse().unwrap(); + let input = SolcVersionedInput::build( + Default::default(), + Default::default(), + SolcLanguage::Solidity, + v.clone(), + ); + let build_info = RawBuildInfo::new(&input, &out_converted, true).unwrap(); + let mut aggregated = AggregatedCompilerOutput::::default(); + aggregated.extend(v, build_info, out_converted); + assert!(!aggregated.is_unchanged()); + } +} diff --git a/crates/project/src/compilers/vyper/mod.rs b/crates/project/src/compilers/vyper/mod.rs index 38c69586..c9f1455a 100644 --- a/crates/project/src/compilers/vyper/mod.rs +++ b/crates/project/src/compilers/vyper/mod.rs @@ -1,9 +1,10 @@ use self::{input::VyperVersionedInput, parser::VyperParsedSource}; use super::{Compiler, CompilerOutput, Language}; use core::fmt; +pub use foundry_compilers_artifacts::vyper::VyperSettings; use foundry_compilers_artifacts::{ sources::Source, - vyper::{error::VyperCompilationError, input::VyperInput, output::VyperOutput, VyperSettings}, + vyper::{error::VyperCompilationError, input::VyperInput, output::VyperOutput}, }; use foundry_compilers_core::error::{Result, SolcError}; use semver::Version; @@ -16,7 +17,7 @@ use std::{ pub mod error; pub mod input; -pub mod output; +mod output; pub mod parser; pub mod settings; diff --git a/crates/project/src/compilers/vyper/settings.rs b/crates/project/src/compilers/vyper/settings.rs index de806907..c0d75640 100644 --- a/crates/project/src/compilers/vyper/settings.rs +++ b/crates/project/src/compilers/vyper/settings.rs @@ -1,5 +1,6 @@ use crate::compilers::CompilerSettings; -use foundry_compilers_artifacts::{output_selection::OutputSelection, vyper::VyperSettings}; +use foundry_compilers_artifacts::output_selection::OutputSelection; +pub use foundry_compilers_artifacts::vyper::VyperSettings; impl CompilerSettings for VyperSettings { fn update_output_selection(&mut self, f: impl FnOnce(&mut OutputSelection)) { diff --git a/crates/project/src/config.rs b/crates/project/src/config.rs index a92a0886..52ec3c4c 100644 --- a/crates/project/src/config.rs +++ b/crates/project/src/config.rs @@ -9,7 +9,7 @@ use foundry_compilers_artifacts::{ output_selection::ContractOutputSelection, remappings::Remapping, sources::{Source, Sources}, - Settings, SolcLanguage, + Libraries, Settings, SolcLanguage, }; use foundry_compilers_core::{ error::{Result, SolcError, SolcIoError}, @@ -552,6 +552,20 @@ impl ProjectPathsConfig { _l: PhantomData, } } + + pub fn apply_lib_remappings(&self, mut libraries: Libraries) -> Libraries { + libraries.libs = libraries.libs + .into_iter() + .map(|(file, target)| { + let file = self.resolve_import(&self.root, &file).unwrap_or_else(|err| { + warn!(target: "libs", "Failed to resolve library `{}` for linking: {:?}", file.display(), err); + file + }); + (file, target) + }) + .collect(); + libraries + } } impl ProjectPathsConfig { diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index b83d4177..be138e86 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -7,6 +7,10 @@ #[macro_use] extern crate tracing; +#[cfg(feature = "project-util")] +#[macro_use] +extern crate foundry_compilers_core; + mod artifact_output; pub use artifact_output::*; @@ -15,21 +19,12 @@ pub mod buildinfo; pub mod cache; pub mod flatten; -use cache::CompilerCache; -use compilers::{multi::MultiCompiler, Compiler, CompilerSettings}; -use foundry_compilers_artifacts::{ - output_selection::OutputSelection, - sources::{Source, Sources}, - Contract, Settings, Severity, SourceFile, StandardJsonCompilerInput, -}; -use foundry_compilers_core::error::{Result, SolcError, SolcIoError}; pub mod resolver; -use output::sources::{VersionedSourceFile, VersionedSourceFiles}; -use project::ProjectCompiler; pub use resolver::Graph; pub mod compilers; +pub use compilers::*; mod compile; pub use compile::{ @@ -44,22 +39,33 @@ mod filter; pub use filter::{ FileFilter, FilteredSources, SourceCompilationKind, SparseOutputFilter, TestFileFilter, }; -use solang_parser::pt::SourceUnitPart; pub mod report; + +/// Utilities for creating, mocking and testing of (temporary) projects +#[cfg(feature = "project-util")] +pub mod project_util; + +use cache::CompilerCache; use compile::output::contracts::VersionedContracts; +use compilers::multi::MultiCompiler; use derivative::Derivative; +use foundry_compilers_artifacts::{ + output_selection::OutputSelection, + sources::{Source, Sources}, + Contract, Settings, Severity, SourceFile, StandardJsonCompilerInput, +}; +use foundry_compilers_core::error::{Result, SolcError, SolcIoError}; +use output::sources::{VersionedSourceFile, VersionedSourceFiles}; +use project::ProjectCompiler; use semver::Version; +use solang_parser::pt::SourceUnitPart; use std::{ collections::{BTreeMap, HashMap, HashSet}, fs, path::{Path, PathBuf}, }; -/// Utilities for creating, mocking and testing of (temporary) projects -#[cfg(feature = "project-util")] -pub mod project_util; - /// Represents a project workspace and handles `solc` compiling of all contracts in that workspace. #[derive(Clone, Derivative)] #[derivative(Debug)] @@ -886,15 +892,17 @@ fn rebase_path(base: impl AsRef, path: impl AsRef) -> PathBuf { #[cfg(test)] #[cfg(feature = "svm-solc")] mod tests { + use foundry_compilers_artifacts::Remapping; + use foundry_compilers_core::utils::{self, mkdir_or_touch, tempdir}; + use super::*; - use crate::remappings::Remapping; #[test] #[cfg_attr(windows, ignore = "<0.7 solc is flaky")] fn test_build_all_versions() { let paths = ProjectPathsConfig::builder() - .root("./test-data/test-contract-versions") - .sources("./test-data/test-contract-versions") + .root("../../test-data/test-contract-versions") + .sources("../../test-data/test-contract-versions") .build() .unwrap(); let project = Project::builder() @@ -910,7 +918,7 @@ mod tests { #[test] fn test_build_many_libs() { - let root = utils::canonicalize("./test-data/test-contract-libs").unwrap(); + let root = utils::canonicalize("../../test-data/test-contract-libs").unwrap(); let paths = ProjectPathsConfig::builder() .root(&root) @@ -937,7 +945,7 @@ mod tests { #[test] fn test_build_remappings() { - let root = utils::canonicalize("./test-data/test-contract-remappings").unwrap(); + let root = utils::canonicalize("../../test-data/test-contract-remappings").unwrap(); let paths = ProjectPathsConfig::builder() .root(&root) .sources(root.join("src")) @@ -993,4 +1001,39 @@ mod tests { PathBuf::from("../remapped/Parent.sol") ); } + + #[test] + fn can_resolve_oz_remappings() { + let tmp_dir = tempdir("node_modules").unwrap(); + let tmp_dir_node_modules = tmp_dir.path().join("node_modules"); + let paths = [ + "node_modules/@openzeppelin/contracts/interfaces/IERC1155.sol", + "node_modules/@openzeppelin/contracts/finance/VestingWallet.sol", + "node_modules/@openzeppelin/contracts/proxy/Proxy.sol", + "node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol", + ]; + mkdir_or_touch(tmp_dir.path(), &paths[..]); + let remappings = Remapping::find_many(tmp_dir_node_modules); + let mut paths = ProjectPathsConfig::<()>::hardhat(tmp_dir.path()).unwrap(); + paths.remappings = remappings; + + let resolved = paths + .resolve_library_import( + tmp_dir.path(), + Path::new("@openzeppelin/contracts/token/ERC20/IERC20.sol"), + ) + .unwrap(); + assert!(resolved.exists()); + + // adjust remappings + paths.remappings[0].name = "@openzeppelin/".to_string(); + + let resolved = paths + .resolve_library_import( + tmp_dir.path(), + Path::new("@openzeppelin/contracts/token/ERC20/IERC20.sol"), + ) + .unwrap(); + assert!(resolved.exists()); + } } diff --git a/crates/project/src/project_util/mock.rs b/crates/project/src/project_util/mock.rs index 5c810b4e..8edc6427 100644 --- a/crates/project/src/project_util/mock.rs +++ b/crates/project/src/project_util/mock.rs @@ -1,12 +1,7 @@ //! Helpers to generate mock projects -use crate::{ - compilers::{multi::MultiCompilerParsedSource, Language, ParsedSource}, - error::Result, - remappings::Remapping, - resolver::GraphEdges, - Graph, ProjectPathsConfig, SolcError, -}; +use foundry_compilers_artifacts::Remapping; +use foundry_compilers_core::error::{Result, SolcError}; use rand::{ distributions::{Distribution, Uniform}, seq::SliceRandom, @@ -18,6 +13,12 @@ use std::{ path::{Path, PathBuf}, }; +use crate::{ + compilers::{multi::MultiCompilerParsedSource, Language, ParsedSource}, + resolver::GraphEdges, + Graph, ProjectPathsConfig, +}; + /// Represents the layout of a project #[derive(Serialize, Deserialize, Default)] pub struct MockProjectSkeleton { diff --git a/crates/project/src/project_util/mod.rs b/crates/project/src/project_util/mod.rs index 1bb75970..f4ffc294 100644 --- a/crates/project/src/project_util/mod.rs +++ b/crates/project/src/project_util/mod.rs @@ -1,22 +1,22 @@ //! Utilities for mocking project workspaces. use crate::{ - artifacts::Settings, + cache::CompilerCache, compilers::{ multi::{MultiCompiler, MultiCompilerSettings}, Compiler, }, config::ProjectPathsConfigBuilder, - error::{Result, SolcError}, - hh::HardhatArtifacts, - project_util::mock::{MockProjectGenerator, MockProjectSettings}, - remappings::Remapping, + Artifact, ArtifactOutput, Artifacts, ConfigurableArtifacts, HardhatArtifacts, PathStyle, + Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, +}; +use foundry_compilers_artifacts::{ConfigurableContractArtifact, Remapping, Settings}; +use foundry_compilers_core::{ + error::{Result, SolcError, SolcIoError}, utils::{self, tempdir}, - Artifact, ArtifactOutput, Artifacts, CompilerCache, ConfigurableArtifacts, - ConfigurableContractArtifact, PathStyle, Project, ProjectBuilder, ProjectCompileOutput, - ProjectPathsConfig, SolcIoError, }; use fs_extra::{dir, file}; +use mock::{MockProjectGenerator, MockProjectSettings}; use std::{ fmt, path::{Path, PathBuf}, @@ -177,7 +177,8 @@ impl TempProject { /// Creates an initialized dapptools style workspace in a new temporary dir pub fn dapptools_init() -> Result { let mut project = Self::dapptools()?; - let orig_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let orig_root = + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/dapp-sample"); copy_dir(orig_root, project.root())?; project.project_mut().paths.remappings = Remapping::find_many(project.root()); project.project_mut().paths.remappings.iter_mut().for_each(|r| r.slash_path()); diff --git a/crates/project/src/resolver/mod.rs b/crates/project/src/resolver/mod.rs index 57e43e9a..ce5327ac 100644 --- a/crates/project/src/resolver/mod.rs +++ b/crates/project/src/resolver/mod.rs @@ -926,7 +926,7 @@ mod tests { #[test] fn can_resolve_hardhat_dependency_graph() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/hardhat-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/hardhat-sample"); let paths = ProjectPathsConfig::hardhat(root).unwrap(); let graph = Graph::::resolve(&paths).unwrap(); @@ -945,7 +945,7 @@ mod tests { #[test] fn can_resolve_dapp_dependency_graph() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/dapp-sample"); let paths = ProjectPathsConfig::dapptools(root).unwrap(); let graph = Graph::::resolve(&paths).unwrap(); @@ -973,7 +973,7 @@ mod tests { #[test] #[cfg(not(target_os = "windows"))] fn can_print_dapp_sample_graph() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/dapp-sample"); let paths = ProjectPathsConfig::dapptools(root).unwrap(); let graph = Graph::::resolve(&paths).unwrap(); let mut out = Vec::::new(); @@ -996,7 +996,7 @@ src/Dapp.t.sol >=0.6.6 #[test] #[cfg(not(target_os = "windows"))] fn can_print_hardhat_sample_graph() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/hardhat-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/hardhat-sample"); let paths = ProjectPathsConfig::hardhat(root).unwrap(); let graph = Graph::::resolve(&paths).unwrap(); let mut out = Vec::::new(); diff --git a/tests/mocked.rs b/crates/project/tests/mocked.rs similarity index 98% rename from tests/mocked.rs rename to crates/project/tests/mocked.rs index d72ec1fe..4fb59dc2 100644 --- a/tests/mocked.rs +++ b/crates/project/tests/mocked.rs @@ -1,8 +1,8 @@ //! mocked project tests -use foundry_compilers::{ +use foundry_compilers_core::error::Result; +use foundry_compilers_project::{ compilers::multi::MultiCompiler, - error::Result, project_util::{ mock::{MockProjectGenerator, MockProjectSettings, MockProjectSkeleton}, TempProject, diff --git a/tests/project.rs b/crates/project/tests/project.rs similarity index 96% rename from tests/project.rs rename to crates/project/tests/project.rs index 43b97067..a9dfabd4 100644 --- a/tests/project.rs +++ b/crates/project/tests/project.rs @@ -1,31 +1,31 @@ //! project tests use alloy_primitives::{Address, Bytes}; -use foundry_compilers::{ - artifacts::{ - output_selection::OutputSelection, BytecodeHash, DevDoc, Error, ErrorDoc, EventDoc, - Libraries, MethodDoc, ModelCheckerEngine::CHC, ModelCheckerSettings, Settings, Severity, - UserDoc, UserDocNotice, - }, +use foundry_compilers_artifacts::{ + output_selection::OutputSelection, remappings::Remapping, BytecodeHash, DevDoc, Error, + ErrorDoc, EventDoc, Libraries, MethodDoc, ModelCheckerEngine::CHC, ModelCheckerSettings, + Settings, Severity, SolcInput, UserDoc, UserDocNotice, +}; +use foundry_compilers_core::{ + error::SolcError, + utils::{self, canonicalize, RuntimeOrHandle}, +}; +use foundry_compilers_project::{ buildinfo::BuildInfo, cache::{CompilerCache, SOLIDITY_FILES_CACHE_FILENAME}, compilers::{ multi::{ MultiCompiler, MultiCompilerLanguage, MultiCompilerParsedSource, MultiCompilerSettings, }, - solc::{SolcCompiler, SolcLanguage}, + solc::{Solc, SolcCompiler, SolcLanguage}, vyper::{Vyper, VyperLanguage, VyperSettings}, CompilerOutput, }, - error::SolcError, flatten::Flattener, info::ContractInfo, project_util::*, - remappings::Remapping, - take_solc_installer_lock, - utils::{self, RuntimeOrHandle}, - Artifact, ConfigurableArtifacts, ExtraOutputValues, Graph, Project, ProjectBuilder, - ProjectCompileOutput, ProjectPathsConfig, Solc, SolcInput, TestFileFilter, + take_solc_installer_lock, Artifact, ConfigurableArtifacts, ExtraOutputValues, Graph, Project, + ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, TestFileFilter, }; use once_cell::sync::Lazy; use pretty_assertions::assert_eq; @@ -75,7 +75,8 @@ pub static VYPER: Lazy = Lazy::new(|| { #[test] fn can_get_versioned_linkrefs() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/test-versioned-linkrefs"); + let root = + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/test-versioned-linkrefs"); let paths = ProjectPathsConfig::builder() .sources(root.join("src")) .lib(root.join("lib")) @@ -93,7 +94,7 @@ fn can_get_versioned_linkrefs() { #[test] fn can_compile_hardhat_sample() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/hardhat-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/hardhat-sample"); let paths = ProjectPathsConfig::builder() .sources(root.join("contracts")) .lib(root.join("node_modules")); @@ -120,7 +121,7 @@ fn can_compile_hardhat_sample() { #[test] fn can_compile_dapp_sample() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/dapp-sample"); let paths = ProjectPathsConfig::builder().sources(root.join("src")).lib(root.join("lib")); let project = TempProject::::new(paths).unwrap(); @@ -147,7 +148,7 @@ fn can_compile_dapp_sample() { #[test] fn can_compile_yul_sample() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/yul-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/yul-sample"); let paths = ProjectPathsConfig::builder().sources(root); let project = TempProject::::new(paths).unwrap(); @@ -177,7 +178,7 @@ fn can_compile_yul_sample() { #[test] fn can_compile_configured() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/dapp-sample"); let paths = ProjectPathsConfig::builder().sources(root.join("src")).lib(root.join("lib")); let handler = ConfigurableArtifacts { @@ -458,8 +459,8 @@ fn can_compile_dapp_sample_with_cache() { let artifacts = root.join("out"); let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let orig_root = manifest_dir.join("test-data/dapp-sample"); - let cache_testdata_dir = manifest_dir.join("test-data/cache-sample/"); + let orig_root = manifest_dir.join("../../test-data/dapp-sample"); + let cache_testdata_dir = manifest_dir.join("../../test-data/cache-sample/"); copy_dir_all(orig_root, &tmp_dir).unwrap(); let paths = ProjectPathsConfig::builder() .cache(cache) @@ -540,10 +541,11 @@ fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> io::Result<()> // Runs both `flatten` implementations, asserts that their outputs match and runs additional checks // against the output. fn test_flatteners(project: &TempProject, target: &Path, additional_checks: fn(&str)) { + let target = canonicalize(target).unwrap(); let result = - project.project().paths.clone().with_language::().flatten(target).unwrap(); + project.project().paths.clone().with_language::().flatten(&target).unwrap(); let solc_result = - Flattener::new(project.project(), &project.compile().unwrap(), target).unwrap().flatten(); + Flattener::new(project.project(), &project.compile().unwrap(), &target).unwrap().flatten(); assert_eq!(result, solc_result); @@ -552,7 +554,7 @@ fn test_flatteners(project: &TempProject, target: &Path, additional_checks: fn(& #[test] fn can_flatten_file_with_external_lib() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/hardhat-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/hardhat-sample"); let paths = ProjectPathsConfig::builder() .sources(root.join("contracts")) .lib(root.join("node_modules")); @@ -569,7 +571,7 @@ fn can_flatten_file_with_external_lib() { #[test] fn can_flatten_file_in_dapp_sample() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/dapp-sample"); let paths = ProjectPathsConfig::builder().sources(root.join("src")).lib(root.join("lib")); let project = TempProject::::new(paths).unwrap(); @@ -2008,7 +2010,8 @@ library MyLib { let libs = Libraries::parse(&[format!("./src/MyLib.sol:MyLib:{:?}", Address::ZERO)]).unwrap(); // provide the library settings to let solc link - tmp.project_mut().settings.solc.libraries = libs.with_applied_remappings(tmp.paths()); + tmp.project_mut().settings.solc.libraries = + libs.apply(|libs| tmp.paths().apply_lib_remappings(libs)); let compiled = tmp.compile().unwrap(); compiled.assert_success(); @@ -2113,7 +2116,8 @@ library MyLib { let libs = Libraries::parse(&[format!("remapping/MyLib.sol:MyLib:{:?}", Address::ZERO)]).unwrap(); // provide the library settings to let solc link - tmp.project_mut().settings.solc.libraries = libs.with_applied_remappings(tmp.paths()); + tmp.project_mut().settings.solc.libraries = + libs.apply(|libs| tmp.paths().apply_lib_remappings(libs)); tmp.project_mut().settings.solc.libraries.slash_paths(); let compiled = tmp.compile().unwrap(); @@ -2732,7 +2736,8 @@ fn can_create_standard_json_input_with_symlink() { #[test] fn can_compile_model_checker_sample() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/model-checker-sample"); + let root = + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/model-checker-sample"); let paths = ProjectPathsConfig::builder().sources(root); let mut project = TempProject::::new(paths).unwrap(); @@ -2751,8 +2756,8 @@ fn can_compile_model_checker_sample() { #[test] fn test_compiler_severity_filter() { fn gen_test_data_warning_path() -> ProjectPathsConfig { - let root = - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/test-contract-warnings"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../../test-data/test-contract-warnings"); ProjectPathsConfig::builder().sources(root).build().unwrap() } @@ -2771,7 +2776,7 @@ fn test_compiler_severity_filter() { .no_artifacts() .paths(gen_test_data_warning_path()) .ephemeral() - .set_compiler_severity_filter(foundry_compilers::artifacts::Severity::Warning) + .set_compiler_severity_filter(foundry_compilers_artifacts::Severity::Warning) .build(Default::default()) .unwrap(); let compiled = project.compile().unwrap(); @@ -2780,14 +2785,17 @@ fn test_compiler_severity_filter() { } fn gen_test_data_licensing_warning() -> ProjectPathsConfig { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("test-data/test-contract-warnings/LicenseWarning.sol"); + let root = canonicalize( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../../test-data/test-contract-warnings/LicenseWarning.sol"), + ) + .unwrap(); ProjectPathsConfig::builder().sources(root).build().unwrap() } fn compile_project_with_options( - severity_filter: Option, + severity_filter: Option, ignore_paths: Option>, ignore_error_code: Option, ) -> ProjectCompileOutput { @@ -2815,11 +2823,15 @@ fn test_compiler_ignored_file_paths() { assert!(compiled.has_compiler_warnings()); compiled.assert_success(); + let testdata = canonicalize( + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data"), + ).unwrap(); let compiled = compile_project_with_options( - Some(foundry_compilers::artifacts::Severity::Warning), - Some(vec![PathBuf::from("test-data")]), + Some(foundry_compilers_artifacts::Severity::Warning), + Some(vec![testdata]), None, ); + // ignored paths set, so the warning shouldnt be present assert!(!compiled.has_compiler_warnings()); compiled.assert_success(); @@ -2837,7 +2849,7 @@ fn test_compiler_severity_filter_and_ignored_error_codes() { compiled.assert_success(); let compiled = compile_project_with_options( - Some(foundry_compilers::artifacts::Severity::Warning), + Some(foundry_compilers_artifacts::Severity::Warning), None, Some(missing_license_error_code), ); @@ -3797,7 +3809,7 @@ contract D { fn test_deterministic_metadata() { let tmp_dir = tempfile::tempdir().unwrap(); let root = tmp_dir.path(); - let orig_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample"); + let orig_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/dapp-sample"); copy_dir_all(orig_root, &tmp_dir).unwrap(); let paths = ProjectPathsConfig::builder().root(root).build().unwrap(); @@ -3814,7 +3826,8 @@ fn test_deterministic_metadata() { let bytecode = artifact.bytecode.as_ref().unwrap().bytes().unwrap().clone(); let expected_bytecode = Bytes::from_str( &std::fs::read_to_string( - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-test-bytecode.txt"), + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../../test-data/dapp-test-bytecode.txt"), ) .unwrap(), ) @@ -3829,7 +3842,7 @@ fn can_compile_vyper_with_cache() { let cache = root.join("cache").join(SOLIDITY_FILES_CACHE_FILENAME); let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let orig_root = manifest_dir.join("test-data/vyper-sample"); + let orig_root = manifest_dir.join("../../test-data/vyper-sample"); copy_dir_all(orig_root, &tmp_dir).unwrap(); let paths = ProjectPathsConfig::builder() @@ -3870,7 +3883,7 @@ fn can_compile_vyper_with_cache() { #[test] fn yul_remappings_ignored() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/yul-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/yul-sample"); // Add dummy remapping. let paths = ProjectPathsConfig::builder().sources(root.clone()).remapping(Remapping { context: None, @@ -3885,7 +3898,7 @@ fn yul_remappings_ignored() { #[test] fn test_vyper_imports() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/vyper-imports"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/vyper-imports"); let paths = ProjectPathsConfig::builder() .sources(root.join("src")) @@ -3910,7 +3923,10 @@ fn test_vyper_imports() { #[test] fn test_can_compile_multi() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/multi-sample"); + let root = canonicalize( + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/multi-sample"), + ) + .unwrap(); let paths = ProjectPathsConfig::builder() .sources(root.join("src")) From 7da6d0b3fb2770088b37718115396b01e3e7d226 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:09:36 +0300 Subject: [PATCH 03/22] update descriptions --- crates/core/Cargo.toml | 2 +- crates/project/Cargo.toml | 2 +- crates/project/README.md | 0 crates/project/src/lib.rs | 2 +- crates/project/tests/project.rs | 5 ++--- 5 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 crates/project/README.md diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index a8b24888..94b4b0ed 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "foundry-compilers-core" -description = "Rust bindings for Solc and Vyper JSON artifacts" +description = "Core utilities for foundry-compilers crates" version.workspace = true edition.workspace = true diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 6f136179..02cb41d2 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "foundry-compilers-project" -description = "Compiler abstraction and implementations for Solc and Vyper" +description = "Compiler abstraction and Foundry project implementation" version.workspace = true edition.workspace = true diff --git a/crates/project/README.md b/crates/project/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index be138e86..a834f862 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -1,4 +1,4 @@ -#![doc = include_str!("../README.md")] +#![doc = include_str!("../../../README.md")] #![warn(rustdoc::all)] #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![deny(unused_must_use, rust_2018_idioms)] diff --git a/crates/project/tests/project.rs b/crates/project/tests/project.rs index a9dfabd4..6faa8e15 100644 --- a/crates/project/tests/project.rs +++ b/crates/project/tests/project.rs @@ -2823,9 +2823,8 @@ fn test_compiler_ignored_file_paths() { assert!(compiled.has_compiler_warnings()); compiled.assert_success(); - let testdata = canonicalize( - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data"), - ).unwrap(); + let testdata = + canonicalize(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data")).unwrap(); let compiled = compile_project_with_options( Some(foundry_compilers_artifacts::Severity::Warning), Some(vec![testdata]), From 80e78720ba0573a1fd1ce0220a3f3b1fa37afe54 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:23:51 +0300 Subject: [PATCH 04/22] fix tests --- crates/artifacts/src/lib.rs | 19 ------------------- crates/core/Cargo.toml | 2 +- crates/core/src/utils.rs | 2 +- crates/project/Cargo.toml | 1 + 4 files changed, 3 insertions(+), 21 deletions(-) diff --git a/crates/artifacts/src/lib.rs b/crates/artifacts/src/lib.rs index 82b9ab84..c7dc396b 100644 --- a/crates/artifacts/src/lib.rs +++ b/crates/artifacts/src/lib.rs @@ -624,25 +624,6 @@ impl Libraries { f(self) } - /// Solc expects the lib paths to match the global path after remappings were applied - /// - /// See also [ProjectPathsConfig::resolve_import] - #[cfg(ignore)] - pub fn with_applied_remappings(mut self, config: &ProjectPathsConfig) -> Self { - self.libs = self - .libs - .into_iter() - .map(|(file, target)| { - let file = config.resolve_import(&config.root, &file).unwrap_or_else(|err| { - warn!(target: "libs", "Failed to resolve library `{}` for linking: {:?}", file.display(), err); - file - }); - (file, target) - }) - .collect(); - self - } - /// Strips the given prefix from all library file paths to make them relative to the given /// `base` argument pub fn with_stripped_file_prefixes(mut self, base: impl AsRef) -> Self { diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 94b4b0ed..90a5925f 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -45,4 +45,4 @@ solang-parser.workspace = true project-util = ["dep:tempfile", "dep:fs_extra"] svm-solc = ["dep:svm", "dep:tokio"] async = ["dep:tokio"] -test-utils = [] \ No newline at end of file +test-utils = ["dep:tempfile"] \ No newline at end of file diff --git a/crates/core/src/utils.rs b/crates/core/src/utils.rs index 604f7525..be168174 100644 --- a/crates/core/src/utils.rs +++ b/crates/core/src/utils.rs @@ -570,7 +570,7 @@ cfg_if! { } /// Creates a new named tempdir. -#[cfg(any(test, feature = "project-util"))] +#[cfg(any(test, feature = "project-util", feature = "test-utils"))] pub fn tempdir(name: &str) -> Result { tempfile::Builder::new().prefix(name).tempdir().map_err(|err| SolcIoError::new(err, name)) } diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 02cb41d2..553e5e00 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -64,6 +64,7 @@ pretty_assertions.workspace = true fd-lock = "4.0.0" tokio = { version = "1.35", features = ["rt-multi-thread", "macros"] } reqwest = "0.12" +tempfile = "3.9" [features] default = ["rustls"] From 512c46db9c04c4ba9802b1af03f30d1334701f41 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:34:17 +0300 Subject: [PATCH 05/22] fix tests --- crates/core/src/utils.rs | 25 --------------------- crates/project/src/compilers/solc/mod.rs | 25 +++++++++++++++++++++ crates/project/src/resolver/mod.rs | 28 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/crates/core/src/utils.rs b/crates/core/src/utils.rs index be168174..1958b273 100644 --- a/crates/core/src/utils.rs +++ b/crates/core/src/utils.rs @@ -682,31 +682,6 @@ mod tests { assert_eq!(found, existing); } - #[cfg(target_os = "linux")] - #[test] - fn can_read_different_case() { - use crate::resolver::parse::SolData; - - let tmp_dir = tempdir("out").unwrap(); - let path = tmp_dir.path().join("forge-std"); - create_dir_all(&path).unwrap(); - let existing = path.join("Test.sol"); - let non_existing = path.join("test.sol"); - fs::write( - existing, - " -pragma solidity ^0.8.10; -contract A {} - ", - ) - .unwrap(); - - assert!(!non_existing.exists()); - - let found = crate::resolver::Node::::read(&non_existing).unwrap_err(); - matches!(found, SolcError::ResolveCaseSensitiveFileName { .. }); - } - #[test] fn can_create_parent_dirs_with_ext() { let tmp_dir = tempdir("out").unwrap(); diff --git a/crates/project/src/compilers/solc/mod.rs b/crates/project/src/compilers/solc/mod.rs index db6bf7c3..13aa6c4c 100644 --- a/crates/project/src/compilers/solc/mod.rs +++ b/crates/project/src/compilers/solc/mod.rs @@ -321,4 +321,29 @@ mod tests { aggregated.extend(v, build_info, out_converted); assert!(!aggregated.is_unchanged()); } + + #[cfg(target_os = "linux")] + #[test] + fn can_read_different_case() { + use crate::resolver::parse::SolData; + + let tmp_dir = tempdir("out").unwrap(); + let path = tmp_dir.path().join("forge-std"); + create_dir_all(&path).unwrap(); + let existing = path.join("Test.sol"); + let non_existing = path.join("test.sol"); + fs::write( + existing, + " +pragma solidity ^0.8.10; +contract A {} + ", + ) + .unwrap(); + + assert!(!non_existing.exists()); + + let found = crate::resolver::Node::::read(&non_existing).unwrap_err(); + matches!(found, SolcError::ResolveCaseSensitiveFileName { .. }); + } } diff --git a/crates/project/src/resolver/mod.rs b/crates/project/src/resolver/mod.rs index ce5327ac..1b73013d 100644 --- a/crates/project/src/resolver/mod.rs +++ b/crates/project/src/resolver/mod.rs @@ -922,6 +922,9 @@ enum SourceVersionError { #[cfg(test)] mod tests { + use std::fs::{self, create_dir_all}; + use utils::tempdir; + use super::*; #[test] @@ -1008,4 +1011,29 @@ src/Dapp.t.sol >=0.6.6 String::from_utf8(out).unwrap() ); } + + #[cfg(target_os = "linux")] + #[test] + fn can_read_different_case() { + use crate::resolver::parse::SolData; + + let tmp_dir = tempdir("out").unwrap(); + let path = tmp_dir.path().join("forge-std"); + create_dir_all(&path).unwrap(); + let existing = path.join("Test.sol"); + let non_existing = path.join("test.sol"); + fs::write( + existing, + " +pragma solidity ^0.8.10; +contract A {} + ", + ) + .unwrap(); + + assert!(!non_existing.exists()); + + let found = crate::resolver::Node::::read(&non_existing).unwrap_err(); + matches!(found, SolcError::ResolveCaseSensitiveFileName { .. }); + } } From 987cc0f25591b9db7b08a6f2f3a5730f3e45da44 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:35:38 +0300 Subject: [PATCH 06/22] fix tests --- crates/core/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 90a5925f..38a68125 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -27,6 +27,7 @@ regex.workspace = true path-slash.workspace = true alloy-primitives.workspace = true once_cell.workspace = true +path-slash.workspace = true svm = { workspace = true, optional = true } tokio = { workspace = true, optional = true } From 7f3c4f1a14d0bc0954496dcd2ef11f0b6f89360b Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:37:13 +0300 Subject: [PATCH 07/22] fix tempfile --- Cargo.toml | 1 + crates/core/Cargo.toml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7ba4dacc..e94d8be8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ once_cell = "1.19" svm = { package = "svm-rs", version = "0.5", default-features = false } solang-parser = { version = "=0.3.3", default-features = false } pretty_assertions = "1" +tempfile = "3.9" # async futures-util = "0.3" diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 38a68125..f914f777 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -36,11 +36,12 @@ dunce = "1.0" memmap2 = "0.9" cfg-if = "1.0.0" -tempfile = { version = "3.9", optional = true } +tempfile = { workspace = true, optional = true } fs_extra = { version = "1.3", optional = true } [dev_dependencies] solang-parser.workspace = true +tempfile.workspace = true [features] project-util = ["dep:tempfile", "dep:fs_extra"] From 03ea61836ebdef68af1b37db8d4aa28a0ae32335 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:39:24 +0300 Subject: [PATCH 08/22] fix Cargo.toml --- crates/artifacts/Cargo.toml | 1 + crates/core/Cargo.toml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/artifacts/Cargo.toml b/crates/artifacts/Cargo.toml index 82a074a4..034b07a0 100644 --- a/crates/artifacts/Cargo.toml +++ b/crates/artifacts/Cargo.toml @@ -31,6 +31,7 @@ rayon.workspace = true thiserror.workspace = true md-5.workspace = true yansi.workspace = true +path-slash.workspace = true futures-util = { workspace = true, optional = true} tokio = { workspace = true, optional = true } diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index f914f777..c65bd3a0 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -27,7 +27,6 @@ regex.workspace = true path-slash.workspace = true alloy-primitives.workspace = true once_cell.workspace = true -path-slash.workspace = true svm = { workspace = true, optional = true } tokio = { workspace = true, optional = true } From 55cecfcb4814e5e11c52fe15f08246ce22e1bc7c Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:41:10 +0300 Subject: [PATCH 09/22] fixes --- crates/artifacts/Cargo.toml | 4 +++- crates/project/src/resolver/mod.rs | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/artifacts/Cargo.toml b/crates/artifacts/Cargo.toml index 034b07a0..8a00c261 100644 --- a/crates/artifacts/Cargo.toml +++ b/crates/artifacts/Cargo.toml @@ -31,12 +31,14 @@ rayon.workspace = true thiserror.workspace = true md-5.workspace = true yansi.workspace = true -path-slash.workspace = true futures-util = { workspace = true, optional = true} tokio = { workspace = true, optional = true } walkdir = "2.4" +[target.'cfg(windows)'.dependencies] +path-slash.workspace = true + [dev_dependencies] serde_path_to_error = "0.1" pretty_assertions.workspace = true diff --git a/crates/project/src/resolver/mod.rs b/crates/project/src/resolver/mod.rs index 1b73013d..78bbd2a6 100644 --- a/crates/project/src/resolver/mod.rs +++ b/crates/project/src/resolver/mod.rs @@ -922,9 +922,6 @@ enum SourceVersionError { #[cfg(test)] mod tests { - use std::fs::{self, create_dir_all}; - use utils::tempdir; - use super::*; #[test] @@ -1016,6 +1013,8 @@ src/Dapp.t.sol >=0.6.6 #[test] fn can_read_different_case() { use crate::resolver::parse::SolData; + use std::fs::{self, create_dir_all}; + use utils::tempdir; let tmp_dir = tempdir("out").unwrap(); let path = tmp_dir.path().join("forge-std"); From cee53b327647318e236cd699f5d0b4a79061da74 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:46:03 +0300 Subject: [PATCH 10/22] fix --- crates/project/src/compilers/solc/mod.rs | 25 ------------------------ 1 file changed, 25 deletions(-) diff --git a/crates/project/src/compilers/solc/mod.rs b/crates/project/src/compilers/solc/mod.rs index 13aa6c4c..db6bf7c3 100644 --- a/crates/project/src/compilers/solc/mod.rs +++ b/crates/project/src/compilers/solc/mod.rs @@ -321,29 +321,4 @@ mod tests { aggregated.extend(v, build_info, out_converted); assert!(!aggregated.is_unchanged()); } - - #[cfg(target_os = "linux")] - #[test] - fn can_read_different_case() { - use crate::resolver::parse::SolData; - - let tmp_dir = tempdir("out").unwrap(); - let path = tmp_dir.path().join("forge-std"); - create_dir_all(&path).unwrap(); - let existing = path.join("Test.sol"); - let non_existing = path.join("test.sol"); - fs::write( - existing, - " -pragma solidity ^0.8.10; -contract A {} - ", - ) - .unwrap(); - - assert!(!non_existing.exists()); - - let found = crate::resolver::Node::::read(&non_existing).unwrap_err(); - matches!(found, SolcError::ResolveCaseSensitiveFileName { .. }); - } } From 2674250d5b67b97081a62df64b3aa3328cb75aed Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:48:07 +0300 Subject: [PATCH 11/22] fmt --- crates/project/src/resolver/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/project/src/resolver/mod.rs b/crates/project/src/resolver/mod.rs index 78bbd2a6..0a553d70 100644 --- a/crates/project/src/resolver/mod.rs +++ b/crates/project/src/resolver/mod.rs @@ -1014,7 +1014,7 @@ src/Dapp.t.sol >=0.6.6 fn can_read_different_case() { use crate::resolver::parse::SolData; use std::fs::{self, create_dir_all}; - use utils::tempdir; + use utils::tempdir; let tmp_dir = tempdir("out").unwrap(); let path = tmp_dir.path().join("forge-std"); From 9d574a32f3ff9e62cd9c4d642acc9d06f0a3efbf Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 03:49:58 +0300 Subject: [PATCH 12/22] fmt --- crates/artifacts/src/sources.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/artifacts/src/sources.rs b/crates/artifacts/src/sources.rs index b4e4a79e..d02ee564 100644 --- a/crates/artifacts/src/sources.rs +++ b/crates/artifacts/src/sources.rs @@ -19,9 +19,9 @@ pub type Sources = BTreeMap; pub struct Source { /// Content of the file /// - /// This is an `Arc` because it may be cloned. If the [Graph](crate::resolver::Graph) of the - /// project contains multiple conflicting versions then the same [Source] may be required by - /// conflicting versions and needs to be duplicated. + /// This is an `Arc` because it may be cloned. If the graph of the project contains multiple + /// conflicting versions then the same [Source] may be required by conflicting versions and + /// needs to be duplicated. pub content: Arc, } From eb94f228403edf037f323cc009d6acc9cf43906a Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 04:00:44 +0300 Subject: [PATCH 13/22] fix features --- crates/project/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 553e5e00..9c391eb6 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -65,6 +65,7 @@ fd-lock = "4.0.0" tokio = { version = "1.35", features = ["rt-multi-thread", "macros"] } reqwest = "0.12" tempfile = "3.9" +foundry-compilers-core = { workspace = true, features = ["test-utils"] } [features] default = ["rustls"] From 0695cff1e3f4007d181479e643a8863d5694c3d8 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 04:01:23 +0300 Subject: [PATCH 14/22] rm licenses --- crates/artifacts/LICENSE-APACHE | 176 -------------------------------- crates/artifacts/LICENSE-MIT | 19 ---- crates/core/LICENSE-APACHE | 176 -------------------------------- crates/core/LICENSE-MIT | 19 ---- crates/project/LICENSE-APACHE | 176 -------------------------------- crates/project/LICENSE-MIT | 19 ---- 6 files changed, 585 deletions(-) delete mode 100644 crates/artifacts/LICENSE-APACHE delete mode 100644 crates/artifacts/LICENSE-MIT delete mode 100644 crates/core/LICENSE-APACHE delete mode 100644 crates/core/LICENSE-MIT delete mode 100644 crates/project/LICENSE-APACHE delete mode 100644 crates/project/LICENSE-MIT diff --git a/crates/artifacts/LICENSE-APACHE b/crates/artifacts/LICENSE-APACHE deleted file mode 100644 index d9a10c0d..00000000 --- a/crates/artifacts/LICENSE-APACHE +++ /dev/null @@ -1,176 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS diff --git a/crates/artifacts/LICENSE-MIT b/crates/artifacts/LICENSE-MIT deleted file mode 100644 index cb2a219b..00000000 --- a/crates/artifacts/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2020 Georgios Konstantopoulos - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/crates/core/LICENSE-APACHE b/crates/core/LICENSE-APACHE deleted file mode 100644 index d9a10c0d..00000000 --- a/crates/core/LICENSE-APACHE +++ /dev/null @@ -1,176 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS diff --git a/crates/core/LICENSE-MIT b/crates/core/LICENSE-MIT deleted file mode 100644 index cb2a219b..00000000 --- a/crates/core/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2020 Georgios Konstantopoulos - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/crates/project/LICENSE-APACHE b/crates/project/LICENSE-APACHE deleted file mode 100644 index d9a10c0d..00000000 --- a/crates/project/LICENSE-APACHE +++ /dev/null @@ -1,176 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS diff --git a/crates/project/LICENSE-MIT b/crates/project/LICENSE-MIT deleted file mode 100644 index cb2a219b..00000000 --- a/crates/project/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2020 Georgios Konstantopoulos - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. From 416e2cadf37e1cfcc345210d425478b95fc76138 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 04:08:13 +0300 Subject: [PATCH 15/22] fix docs --- crates/project/src/artifact_output/configurable.rs | 4 ++-- crates/project/src/cache.rs | 2 +- crates/project/src/compile/output/mod.rs | 6 +++--- crates/project/src/compile/project.rs | 2 +- crates/project/src/config.rs | 9 +++++---- crates/project/src/report/compiler.rs | 2 +- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/crates/project/src/artifact_output/configurable.rs b/crates/project/src/artifact_output/configurable.rs index 14b69154..6b45dfed 100644 --- a/crates/project/src/artifact_output/configurable.rs +++ b/crates/project/src/artifact_output/configurable.rs @@ -5,8 +5,8 @@ //! `ConfigurableArtifacts` populates a single `Artifact`, the `ConfigurableArtifact`, by default //! with essential entries only, such as `abi`, `bytecode`,..., but may include additional values //! based on its `ExtraOutputValues` that maps to various objects in the solc contract output, see -//! also: [`OutputSelection`](crate::artifacts::output_selection::OutputSelection). In addition to -//! that some output values can also be emitted as standalone files. +//! also: [`OutputSelection`](foundry_compilers_artifacts::output_selection::OutputSelection). In +//! addition to that some output values can also be emitted as standalone files. use crate::{ sources::VersionedSourceFile, Artifact, ArtifactFile, ArtifactOutput, SolcConfig, SolcError, diff --git a/crates/project/src/cache.rs b/crates/project/src/cache.rs index b0dc7ea0..95782ad3 100644 --- a/crates/project/src/cache.rs +++ b/crates/project/src/cache.rs @@ -402,7 +402,7 @@ pub struct CacheEntry { pub last_modification_date: u64, /// hash to identify whether the content of the file changed pub content_hash: String, - /// identifier name see [`crate::utils::source_name()`] + /// identifier name see [`foundry_compilers_core::utils::source_name()`] pub source_name: PathBuf, /// what config was set when compiling this file pub compiler_settings: S, diff --git a/crates/project/src/compile/output/mod.rs b/crates/project/src/compile/output/mod.rs index 5932fae3..1c26a703 100644 --- a/crates/project/src/compile/output/mod.rs +++ b/crates/project/src/compile/output/mod.rs @@ -215,8 +215,8 @@ impl ProjectCompileOutput { /// /// Note: this only returns the `SourceFiles` for freshly compiled contracts because, if not /// included in the `Artifact` itself (see - /// [`crate::ConfigurableContractArtifact::source_file()`]), is only available via the solc - /// `CompilerOutput` + /// [`foundry_compilers_artifacts::ConfigurableContractArtifact::source_file()`]), is only + /// available via the solc `CompilerOutput` pub fn into_artifacts_with_sources( self, ) -> (BTreeMap, VersionedSourceFiles) { @@ -456,7 +456,7 @@ impl ProjectCompileOutput { } /// A helper functions that extracts the underlying [`CompactContractBytecode`] from the - /// [`crate::ConfigurableContractArtifact`] + /// [`foundry_compilers_artifacts::ConfigurableContractArtifact`] /// /// # Examples /// diff --git a/crates/project/src/compile/project.rs b/crates/project/src/compile/project.rs index 6ac92fe6..5737f345 100644 --- a/crates/project/src/compile/project.rs +++ b/crates/project/src/compile/project.rs @@ -6,7 +6,7 @@ //! dependencies are resolved. The graph holds all the relationships between the files and their //! versions. From there the appropriate version set is derived //! [`crate::Graph`] which need to be compiled with different -//! [`crate::Solc`] versions. +//! [`crate::compilers::solc::Solc`] versions. //! //! At this point we check if we need to compile a source file or whether we can reuse an _existing_ //! `Artifact`. We don't to compile if: diff --git a/crates/project/src/config.rs b/crates/project/src/config.rs index 52ec3c4c..ea090419 100644 --- a/crates/project/src/config.rs +++ b/crates/project/src/config.rs @@ -477,10 +477,11 @@ impl ProjectPathsConfig { /// /// `import "@openzeppelin/token/ERC20/IERC20.sol";` /// - /// There is no strict rule behind this, but because [`crate::remappings::Remapping::find_many`] - /// returns `'@openzeppelin/=node_modules/@openzeppelin/contracts/'` we should handle the - /// case if the remapping path ends with `contracts` and the import path starts with - /// `/contracts`. Otherwise we can end up with a resolved path that has a + /// There is no strict rule behind this, but because + /// [`foundry_compilers_artifacts::remappings::Remapping::find_many`] returns `'@ + /// openzeppelin/=node_modules/@openzeppelin/contracts/'` we should handle the case if the + /// remapping path ends with `contracts` and the import path starts with `/contracts`. Otherwise we can end up with a resolved path that has a /// duplicate `contracts` segment: /// `@openzeppelin/contracts/contracts/token/ERC20/IERC20.sol` we check for this edge case /// here so that both styles work out of the box. diff --git a/crates/project/src/report/compiler.rs b/crates/project/src/report/compiler.rs index c43050b4..e62d40a6 100644 --- a/crates/project/src/report/compiler.rs +++ b/crates/project/src/report/compiler.rs @@ -9,7 +9,7 @@ use foundry_compilers_artifacts::{CompilerOutput, SolcInput}; use semver::Version; use std::{env, path::PathBuf, str::FromStr}; -/// Debug Helper type that can be used to write the [crate::Solc] [SolcInput] and +/// Debug Helper type that can be used to write the [crate::compilers::solc::Solc] [SolcInput] and /// [CompilerOutput] to disk if configured. /// /// # Examples From a88735d26de4da4703c2c8360b324edd4a4a2c71 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 17:13:36 +0300 Subject: [PATCH 16/22] reexport --- crates/project/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index a834f862..2e7c2d06 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -46,6 +46,8 @@ pub mod report; #[cfg(feature = "project-util")] pub mod project_util; +pub use foundry_compilers_artifacts as artifacts; + use cache::CompilerCache; use compile::output::contracts::VersionedContracts; use compilers::multi::MultiCompiler; From 7577e39c0f8fbf8e4d974a426d371e4426d97a76 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 17:16:59 +0300 Subject: [PATCH 17/22] reexport core --- crates/project/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index 2e7c2d06..08185db8 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -47,6 +47,7 @@ pub mod report; pub mod project_util; pub use foundry_compilers_artifacts as artifacts; +pub use foundry_compilers_core::{error, utils}; use cache::CompilerCache; use compile::output::contracts::VersionedContracts; From 12d31739fef0c9b84d57050e433904f6a8e33b66 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 17:36:22 +0300 Subject: [PATCH 18/22] more reeexports --- crates/artifacts/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/artifacts/src/lib.rs b/crates/artifacts/src/lib.rs index c7dc396b..3baec12d 100644 --- a/crates/artifacts/src/lib.rs +++ b/crates/artifacts/src/lib.rs @@ -33,11 +33,9 @@ pub mod output_selection; pub mod serde_helpers; pub mod sourcemap; pub mod sources; +pub use sources::*; pub mod vyper; -use crate::{ - output_selection::{ContractOutputSelection, OutputSelection}, - sources::{Source, Sources}, -}; +use crate::output_selection::{ContractOutputSelection, OutputSelection}; use foundry_compilers_core::{ error::SolcError, utils::{ From 9e75a75aa9c126cfee34fab0e7bc87d43782a6e1 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Thu, 13 Jun 2024 17:47:37 +0300 Subject: [PATCH 19/22] dev-dependencies --- crates/artifacts/Cargo.toml | 2 +- crates/core/Cargo.toml | 2 +- crates/project/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/artifacts/Cargo.toml b/crates/artifacts/Cargo.toml index 8a00c261..1d1a38ac 100644 --- a/crates/artifacts/Cargo.toml +++ b/crates/artifacts/Cargo.toml @@ -39,7 +39,7 @@ walkdir = "2.4" [target.'cfg(windows)'.dependencies] path-slash.workspace = true -[dev_dependencies] +[dev-dependencies] serde_path_to_error = "0.1" pretty_assertions.workspace = true foundry-compilers-core = { workspace = true, features = ["test-utils"] } diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index c65bd3a0..313195a4 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -38,7 +38,7 @@ cfg-if = "1.0.0" tempfile = { workspace = true, optional = true } fs_extra = { version = "1.3", optional = true } -[dev_dependencies] +[dev-dependencies] solang-parser.workspace = true tempfile.workspace = true diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 9c391eb6..e072cc75 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -55,7 +55,7 @@ svm = { workspace = true, optional = true } svm-builds = { package = "svm-rs-builds", version = "0.5", default-features = false, optional = true } sha2 = { version = "0.10", default-features = false, optional = true } -[dev_dependencies] +[dev-dependencies] tracing-subscriber = { version = "0.3", default-features = false, features = [ "env-filter", "fmt", From 50e636cc3c36850dcd491e9f563203f2e459e0c7 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 14 Jun 2024 08:49:58 +0300 Subject: [PATCH 20/22] extract Vyper artifacts --- Cargo.toml | 1 + crates/artifacts-vyper/Cargo.toml | 35 +++++++++++++++++++ .../vyper => artifacts-vyper/src}/error.rs | 2 +- .../vyper => artifacts-vyper/src}/input.rs | 2 +- .../mod.rs => artifacts-vyper/src/lib.rs} | 12 ++++--- .../vyper => artifacts-vyper/src}/output.rs | 23 ++++++------ .../vyper => artifacts-vyper/src}/settings.rs | 2 +- crates/artifacts/Cargo.toml | 2 +- crates/artifacts/src/lib.rs | 3 +- crates/project/Cargo.toml | 1 + crates/project/src/compilers/multi.rs | 6 ++-- crates/project/src/compilers/vyper/error.rs | 3 +- crates/project/src/compilers/vyper/input.rs | 8 ++--- crates/project/src/compilers/vyper/mod.rs | 9 +++-- crates/project/src/compilers/vyper/output.rs | 2 +- .../project/src/compilers/vyper/settings.rs | 2 +- crates/project/src/lib.rs | 6 +++- 17 files changed, 83 insertions(+), 36 deletions(-) create mode 100644 crates/artifacts-vyper/Cargo.toml rename crates/{artifacts/src/vyper => artifacts-vyper/src}/error.rs (96%) rename crates/{artifacts/src/vyper => artifacts-vyper/src}/input.rs (96%) rename crates/{artifacts/src/vyper/mod.rs => artifacts-vyper/src/lib.rs} (53%) rename crates/{artifacts/src/vyper => artifacts-vyper/src}/output.rs (88%) rename crates/{artifacts/src/vyper => artifacts-vyper/src}/settings.rs (95%) diff --git a/Cargo.toml b/Cargo.toml index e94d8be8..8d3c3874 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ exclude = [".github/", "scripts/", "test-data/"] [workspace.dependencies] foundry-compilers-artifacts = { path = "crates/artifacts", version = "0.7.0" } +foundry-compilers-artifacts-vyper = { path = "crates/artifacts-vyper", version = "0.7.0" } foundry-compilers-core = { path = "crates/core", version = "0.7.0" } serde = { version = "1", features = ["derive", "rc"] } semver = { version = "1.0", features = ["serde"] } diff --git a/crates/artifacts-vyper/Cargo.toml b/crates/artifacts-vyper/Cargo.toml new file mode 100644 index 00000000..4dec0f36 --- /dev/null +++ b/crates/artifacts-vyper/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "foundry-compilers-artifacts-vyper" +description = "Rust bindings for Vyper JSON artifacts" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +exclude.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[package.metadata.playground] +all-features = true + +[dependencies] +foundry-compilers-artifacts.workspace = true + +serde.workspace = true +alloy-primitives.workspace = true +alloy-json-abi.workspace = true + +[target.'cfg(windows)'.dependencies] +path-slash.workspace = true + +[dev-dependencies] +serde_path_to_error = "0.1" +pretty_assertions.workspace = true +foundry-compilers-core = { workspace = true, features = ["test-utils"] } +serde_json.workspace = true \ No newline at end of file diff --git a/crates/artifacts/src/vyper/error.rs b/crates/artifacts-vyper/src/error.rs similarity index 96% rename from crates/artifacts/src/vyper/error.rs rename to crates/artifacts-vyper/src/error.rs index bd037549..21b3b33d 100644 --- a/crates/artifacts/src/vyper/error.rs +++ b/crates/artifacts-vyper/src/error.rs @@ -1,5 +1,5 @@ -use crate::Severity; use core::fmt; +use foundry_compilers_artifacts::Severity; use serde::{Deserialize, Serialize}; use std::path::PathBuf; diff --git a/crates/artifacts/src/vyper/input.rs b/crates/artifacts-vyper/src/input.rs similarity index 96% rename from crates/artifacts/src/vyper/input.rs rename to crates/artifacts-vyper/src/input.rs index 8488b53d..7e61d015 100644 --- a/crates/artifacts/src/vyper/input.rs +++ b/crates/artifacts-vyper/src/input.rs @@ -1,7 +1,7 @@ use std::path::Path; use super::VyperSettings; -use crate::sources::Sources; +use foundry_compilers_artifacts::sources::Sources; use serde::{Deserialize, Serialize}; /// Extension of Vyper interface file. diff --git a/crates/artifacts/src/vyper/mod.rs b/crates/artifacts-vyper/src/lib.rs similarity index 53% rename from crates/artifacts/src/vyper/mod.rs rename to crates/artifacts-vyper/src/lib.rs index e1186bc0..4fd1dbaf 100644 --- a/crates/artifacts/src/vyper/mod.rs +++ b/crates/artifacts-vyper/src/lib.rs @@ -1,11 +1,15 @@ -pub mod settings; +//! Vyper artifact types. + +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +mod settings; pub use settings::{VyperOptimizationMode, VyperSettings}; -pub mod error; +mod error; pub use error::VyperCompilationError; -pub mod input; +mod input; pub use input::VyperInput; -pub mod output; +mod output; pub use output::VyperOutput; diff --git a/crates/artifacts/src/vyper/output.rs b/crates/artifacts-vyper/src/output.rs similarity index 88% rename from crates/artifacts/src/vyper/output.rs rename to crates/artifacts-vyper/src/output.rs index a80a1b8e..6fe04fa6 100644 --- a/crates/artifacts/src/vyper/output.rs +++ b/crates/artifacts-vyper/src/output.rs @@ -1,7 +1,8 @@ use super::error::VyperCompilationError; -use crate::{BytecodeObject, Contract, Evm, FileToContractsMap, SourceFile}; use alloy_json_abi::JsonAbi; use alloy_primitives::Bytes; +use foundry_compilers_artifacts as solc_artifacts; +use foundry_compilers_artifacts::BytecodeObject; use serde::Deserialize; use std::{ collections::{BTreeMap, HashSet}, @@ -19,9 +20,9 @@ pub struct Bytecode { pub source_map: Option, } -impl From for crate::Bytecode { +impl From for solc_artifacts::Bytecode { fn from(bytecode: Bytecode) -> Self { - crate::Bytecode { + solc_artifacts::Bytecode { object: BytecodeObject::Bytecode(bytecode.object), opcodes: bytecode.opcodes, source_map: bytecode.source_map, @@ -44,11 +45,11 @@ pub struct VyperEvm { pub method_identifiers: BTreeMap, } -impl From for Evm { +impl From for solc_artifacts::Evm { fn from(evm: VyperEvm) -> Self { - Evm { + solc_artifacts::Evm { bytecode: evm.bytecode.map(Into::into), - deployed_bytecode: evm.deployed_bytecode.map(|b| crate::DeployedBytecode { + deployed_bytecode: evm.deployed_bytecode.map(|b| solc_artifacts::DeployedBytecode { bytecode: Some(b.into()), immutable_references: Default::default(), }), @@ -69,9 +70,9 @@ pub struct VyperContract { pub evm: Option, } -impl From for Contract { +impl From for solc_artifacts::Contract { fn from(contract: VyperContract) -> Self { - Contract { + solc_artifacts::Contract { abi: contract.abi, evm: contract.evm.map(Into::into), metadata: None, @@ -90,9 +91,9 @@ pub struct VyperSourceFile { pub id: u32, } -impl From for SourceFile { +impl From for solc_artifacts::SourceFile { fn from(source: VyperSourceFile) -> Self { - SourceFile { id: source.id, ast: None } + solc_artifacts::SourceFile { id: source.id, ast: None } } } @@ -102,7 +103,7 @@ pub struct VyperOutput { #[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")] pub errors: Vec, #[serde(default)] - pub contracts: FileToContractsMap, + pub contracts: solc_artifacts::FileToContractsMap, #[serde(default)] pub sources: BTreeMap, } diff --git a/crates/artifacts/src/vyper/settings.rs b/crates/artifacts-vyper/src/settings.rs similarity index 95% rename from crates/artifacts/src/vyper/settings.rs rename to crates/artifacts-vyper/src/settings.rs index 49142e26..ec35250a 100644 --- a/crates/artifacts/src/vyper/settings.rs +++ b/crates/artifacts-vyper/src/settings.rs @@ -1,4 +1,4 @@ -use crate::{output_selection::OutputSelection, serde_helpers, EvmVersion}; +use foundry_compilers_artifacts::{output_selection::OutputSelection, serde_helpers, EvmVersion}; use serde::{Deserialize, Serialize}; use std::path::Path; diff --git a/crates/artifacts/Cargo.toml b/crates/artifacts/Cargo.toml index 1d1a38ac..d67cf9c3 100644 --- a/crates/artifacts/Cargo.toml +++ b/crates/artifacts/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "foundry-compilers-artifacts" -description = "Rust bindings for Solc and Vyper JSON artifacts" +description = "Rust bindings for Solc JSON artifacts" version.workspace = true edition.workspace = true diff --git a/crates/artifacts/src/lib.rs b/crates/artifacts/src/lib.rs index 3baec12d..4983a733 100644 --- a/crates/artifacts/src/lib.rs +++ b/crates/artifacts/src/lib.rs @@ -33,8 +33,6 @@ pub mod output_selection; pub mod serde_helpers; pub mod sourcemap; pub mod sources; -pub use sources::*; -pub mod vyper; use crate::output_selection::{ContractOutputSelection, OutputSelection}; use foundry_compilers_core::{ error::SolcError, @@ -44,6 +42,7 @@ use foundry_compilers_core::{ }, }; pub use serde_helpers::{deserialize_bytes, deserialize_opt_bytes}; +pub use sources::*; /// Solidity files are made up of multiple `source units`, a solidity contract is such a `source /// unit`, therefore a solidity file can contain multiple contracts: (1-N*) relationship. diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index e072cc75..b653ee7d 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -20,6 +20,7 @@ all-features = true [dependencies] foundry-compilers-artifacts.workspace = true +foundry-compilers-artifacts-vyper.workspace = true foundry-compilers-core.workspace = true serde.workspace = true semver.workspace = true diff --git a/crates/project/src/compilers/multi.rs b/crates/project/src/compilers/multi.rs index 8739feb7..49159828 100644 --- a/crates/project/src/compilers/multi.rs +++ b/crates/project/src/compilers/multi.rs @@ -7,13 +7,15 @@ use super::{ CompilationError, Compiler, CompilerInput, CompilerOutput, CompilerSettings, CompilerVersion, Language, ParsedSource, }; -use crate::resolver::parse::SolData; +use crate::{ + artifacts::vyper::{VyperCompilationError, VyperSettings}, + resolver::parse::SolData, +}; use foundry_compilers_artifacts::{ error::SourceLocation, output_selection::OutputSelection, remappings::Remapping, sources::{Source, Sources}, - vyper::{error::VyperCompilationError, VyperSettings}, Error, Settings as SolcSettings, Severity, SolcLanguage, }; use foundry_compilers_core::error::{Result, SolcError}; diff --git a/crates/project/src/compilers/vyper/error.rs b/crates/project/src/compilers/vyper/error.rs index 5b4c385a..63112830 100644 --- a/crates/project/src/compilers/vyper/error.rs +++ b/crates/project/src/compilers/vyper/error.rs @@ -1,6 +1,7 @@ use crate::compilers::CompilationError; +use crate::artifacts::vyper::VyperCompilationError; use foundry_compilers_artifacts::{ - error::SourceLocation, vyper::error::VyperCompilationError, Severity, + error::SourceLocation, Severity, }; impl CompilationError for VyperCompilationError { diff --git a/crates/project/src/compilers/vyper/input.rs b/crates/project/src/compilers/vyper/input.rs index 43f4898a..54db5f4d 100644 --- a/crates/project/src/compilers/vyper/input.rs +++ b/crates/project/src/compilers/vyper/input.rs @@ -1,9 +1,9 @@ use super::VyperLanguage; -use crate::compilers::CompilerInput; -use foundry_compilers_artifacts::{ - sources::{Source, Sources}, - vyper::{input::VyperInput, VyperSettings}, +use crate::{ + artifacts::vyper::{VyperInput, VyperSettings}, + compilers::CompilerInput, }; +use foundry_compilers_artifacts::sources::{Source, Sources}; use semver::Version; use serde::Serialize; use std::{borrow::Cow, path::Path}; diff --git a/crates/project/src/compilers/vyper/mod.rs b/crates/project/src/compilers/vyper/mod.rs index c9f1455a..cc937d05 100644 --- a/crates/project/src/compilers/vyper/mod.rs +++ b/crates/project/src/compilers/vyper/mod.rs @@ -1,11 +1,10 @@ use self::{input::VyperVersionedInput, parser::VyperParsedSource}; use super::{Compiler, CompilerOutput, Language}; -use core::fmt; -pub use foundry_compilers_artifacts::vyper::VyperSettings; -use foundry_compilers_artifacts::{ - sources::Source, - vyper::{error::VyperCompilationError, input::VyperInput, output::VyperOutput}, +pub use crate::artifacts::vyper::{ + VyperCompilationError, VyperInput, VyperOutput, VyperSettings, }; +use core::fmt; +use foundry_compilers_artifacts::sources::Source; use foundry_compilers_core::error::{Result, SolcError}; use semver::Version; use serde::{de::DeserializeOwned, Serialize}; diff --git a/crates/project/src/compilers/vyper/output.rs b/crates/project/src/compilers/vyper/output.rs index b2477fcb..2560c8a5 100644 --- a/crates/project/src/compilers/vyper/output.rs +++ b/crates/project/src/compilers/vyper/output.rs @@ -1,4 +1,4 @@ -use foundry_compilers_artifacts::vyper::{error::VyperCompilationError, output::VyperOutput}; +use crate::artifacts::vyper::{VyperCompilationError, VyperOutput}; impl From for super::CompilerOutput { fn from(output: VyperOutput) -> Self { diff --git a/crates/project/src/compilers/vyper/settings.rs b/crates/project/src/compilers/vyper/settings.rs index c0d75640..287ab991 100644 --- a/crates/project/src/compilers/vyper/settings.rs +++ b/crates/project/src/compilers/vyper/settings.rs @@ -1,6 +1,6 @@ +pub use crate::artifacts::vyper::VyperSettings; use crate::compilers::CompilerSettings; use foundry_compilers_artifacts::output_selection::OutputSelection; -pub use foundry_compilers_artifacts::vyper::VyperSettings; impl CompilerSettings for VyperSettings { fn update_output_selection(&mut self, f: impl FnOnce(&mut OutputSelection)) { diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index 08185db8..76ac902f 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -46,9 +46,13 @@ pub mod report; #[cfg(feature = "project-util")] pub mod project_util; -pub use foundry_compilers_artifacts as artifacts; pub use foundry_compilers_core::{error, utils}; +pub mod artifacts { + pub use foundry_compilers_artifacts::*; + pub use foundry_compilers_artifacts_vyper as vyper; +} + use cache::CompilerCache; use compile::output::contracts::VersionedContracts; use compilers::multi::MultiCompiler; From f0ed28e5f7c62ea65faa0152bdaa838073eb3a50 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 14 Jun 2024 16:58:33 +0300 Subject: [PATCH 21/22] crates/artifacts --- Cargo.toml | 7 ++--- crates/artifacts/artifacts/Cargo.toml | 26 +++++++++++++++++++ crates/artifacts/artifacts/src/lib.rs | 7 +++++ crates/artifacts/{ => solc}/Cargo.toml | 2 +- .../{ => solc}/src/ast/lowfidelity.rs | 0 crates/artifacts/{ => solc}/src/ast/macros.rs | 0 crates/artifacts/{ => solc}/src/ast/misc.rs | 0 crates/artifacts/{ => solc}/src/ast/mod.rs | 0 crates/artifacts/{ => solc}/src/ast/util.rs | 0 .../artifacts/{ => solc}/src/ast/visitor.rs | 0 crates/artifacts/{ => solc}/src/ast/yul.rs | 0 crates/artifacts/{ => solc}/src/bytecode.rs | 0 .../artifacts/{ => solc}/src/configurable.rs | 0 crates/artifacts/{ => solc}/src/contract.rs | 0 crates/artifacts/{ => solc}/src/error.rs | 0 crates/artifacts/{ => solc}/src/hh.rs | 0 crates/artifacts/{ => solc}/src/lib.rs | 0 .../{ => solc}/src/output_selection.rs | 0 crates/artifacts/{ => solc}/src/remappings.rs | 0 .../artifacts/{ => solc}/src/serde_helpers.rs | 0 crates/artifacts/{ => solc}/src/sourcemap.rs | 0 crates/artifacts/{ => solc}/src/sources.rs | 0 .../vyper}/Cargo.toml | 2 +- .../vyper}/src/error.rs | 2 +- .../vyper}/src/input.rs | 2 +- .../vyper}/src/lib.rs | 0 .../vyper}/src/output.rs | 4 +-- .../vyper}/src/settings.rs | 4 ++- crates/project/Cargo.toml | 1 - crates/project/src/compilers/vyper/error.rs | 7 ++--- crates/project/src/compilers/vyper/mod.rs | 4 +-- crates/project/src/flatten.rs | 1 + crates/project/src/lib.rs | 8 ++---- 33 files changed, 52 insertions(+), 25 deletions(-) create mode 100644 crates/artifacts/artifacts/Cargo.toml create mode 100644 crates/artifacts/artifacts/src/lib.rs rename crates/artifacts/{ => solc}/Cargo.toml (96%) rename crates/artifacts/{ => solc}/src/ast/lowfidelity.rs (100%) rename crates/artifacts/{ => solc}/src/ast/macros.rs (100%) rename crates/artifacts/{ => solc}/src/ast/misc.rs (100%) rename crates/artifacts/{ => solc}/src/ast/mod.rs (100%) rename crates/artifacts/{ => solc}/src/ast/util.rs (100%) rename crates/artifacts/{ => solc}/src/ast/visitor.rs (100%) rename crates/artifacts/{ => solc}/src/ast/yul.rs (100%) rename crates/artifacts/{ => solc}/src/bytecode.rs (100%) rename crates/artifacts/{ => solc}/src/configurable.rs (100%) rename crates/artifacts/{ => solc}/src/contract.rs (100%) rename crates/artifacts/{ => solc}/src/error.rs (100%) rename crates/artifacts/{ => solc}/src/hh.rs (100%) rename crates/artifacts/{ => solc}/src/lib.rs (100%) rename crates/artifacts/{ => solc}/src/output_selection.rs (100%) rename crates/artifacts/{ => solc}/src/remappings.rs (100%) rename crates/artifacts/{ => solc}/src/serde_helpers.rs (100%) rename crates/artifacts/{ => solc}/src/sourcemap.rs (100%) rename crates/artifacts/{ => solc}/src/sources.rs (100%) rename crates/{artifacts-vyper => artifacts/vyper}/Cargo.toml (94%) rename crates/{artifacts-vyper => artifacts/vyper}/src/error.rs (96%) rename crates/{artifacts-vyper => artifacts/vyper}/src/input.rs (96%) rename crates/{artifacts-vyper => artifacts/vyper}/src/lib.rs (100%) rename crates/{artifacts-vyper => artifacts/vyper}/src/output.rs (98%) rename crates/{artifacts-vyper => artifacts/vyper}/src/settings.rs (95%) diff --git a/Cargo.toml b/Cargo.toml index 8d3c3874..2a9d146e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["crates/*"] +members = ["crates/artifacts/*", "crates/core", "crates/project"] resolver = "2" [workspace.package] @@ -17,8 +17,9 @@ edition = "2021" exclude = [".github/", "scripts/", "test-data/"] [workspace.dependencies] -foundry-compilers-artifacts = { path = "crates/artifacts", version = "0.7.0" } -foundry-compilers-artifacts-vyper = { path = "crates/artifacts-vyper", version = "0.7.0" } +foundry-compilers-artifacts-solc = { path = "crates/artifacts/solc", version = "0.7.0" } +foundry-compilers-artifacts-vyper = { path = "crates/artifacts/vyper", version = "0.7.0" } +foundry-compilers-artifacts = { path = "crates/artifacts/artifacts", version = "0.7.0" } foundry-compilers-core = { path = "crates/core", version = "0.7.0" } serde = { version = "1", features = ["derive", "rc"] } semver = { version = "1.0", features = ["serde"] } diff --git a/crates/artifacts/artifacts/Cargo.toml b/crates/artifacts/artifacts/Cargo.toml new file mode 100644 index 00000000..057a21f3 --- /dev/null +++ b/crates/artifacts/artifacts/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "foundry-compilers-artifacts" +description = "Rust bindings for compilers JSON artifacts" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +exclude.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[package.metadata.playground] +all-features = true + +[dependencies] +foundry-compilers-artifacts-solc.workspace = true +foundry-compilers-artifacts-vyper.workspace = true + +[features] +async = ["foundry-compilers-artifacts-solc/async"] \ No newline at end of file diff --git a/crates/artifacts/artifacts/src/lib.rs b/crates/artifacts/artifacts/src/lib.rs new file mode 100644 index 00000000..403ab1ee --- /dev/null +++ b/crates/artifacts/artifacts/src/lib.rs @@ -0,0 +1,7 @@ +//! Meta crate reexporting all artifacts types. + +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +pub use foundry_compilers_artifacts_solc as solc; +pub use foundry_compilers_artifacts_vyper as vyper; +pub use solc::*; diff --git a/crates/artifacts/Cargo.toml b/crates/artifacts/solc/Cargo.toml similarity index 96% rename from crates/artifacts/Cargo.toml rename to crates/artifacts/solc/Cargo.toml index d67cf9c3..8a8f4dc4 100644 --- a/crates/artifacts/Cargo.toml +++ b/crates/artifacts/solc/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "foundry-compilers-artifacts" +name = "foundry-compilers-artifacts-solc" description = "Rust bindings for Solc JSON artifacts" version.workspace = true diff --git a/crates/artifacts/src/ast/lowfidelity.rs b/crates/artifacts/solc/src/ast/lowfidelity.rs similarity index 100% rename from crates/artifacts/src/ast/lowfidelity.rs rename to crates/artifacts/solc/src/ast/lowfidelity.rs diff --git a/crates/artifacts/src/ast/macros.rs b/crates/artifacts/solc/src/ast/macros.rs similarity index 100% rename from crates/artifacts/src/ast/macros.rs rename to crates/artifacts/solc/src/ast/macros.rs diff --git a/crates/artifacts/src/ast/misc.rs b/crates/artifacts/solc/src/ast/misc.rs similarity index 100% rename from crates/artifacts/src/ast/misc.rs rename to crates/artifacts/solc/src/ast/misc.rs diff --git a/crates/artifacts/src/ast/mod.rs b/crates/artifacts/solc/src/ast/mod.rs similarity index 100% rename from crates/artifacts/src/ast/mod.rs rename to crates/artifacts/solc/src/ast/mod.rs diff --git a/crates/artifacts/src/ast/util.rs b/crates/artifacts/solc/src/ast/util.rs similarity index 100% rename from crates/artifacts/src/ast/util.rs rename to crates/artifacts/solc/src/ast/util.rs diff --git a/crates/artifacts/src/ast/visitor.rs b/crates/artifacts/solc/src/ast/visitor.rs similarity index 100% rename from crates/artifacts/src/ast/visitor.rs rename to crates/artifacts/solc/src/ast/visitor.rs diff --git a/crates/artifacts/src/ast/yul.rs b/crates/artifacts/solc/src/ast/yul.rs similarity index 100% rename from crates/artifacts/src/ast/yul.rs rename to crates/artifacts/solc/src/ast/yul.rs diff --git a/crates/artifacts/src/bytecode.rs b/crates/artifacts/solc/src/bytecode.rs similarity index 100% rename from crates/artifacts/src/bytecode.rs rename to crates/artifacts/solc/src/bytecode.rs diff --git a/crates/artifacts/src/configurable.rs b/crates/artifacts/solc/src/configurable.rs similarity index 100% rename from crates/artifacts/src/configurable.rs rename to crates/artifacts/solc/src/configurable.rs diff --git a/crates/artifacts/src/contract.rs b/crates/artifacts/solc/src/contract.rs similarity index 100% rename from crates/artifacts/src/contract.rs rename to crates/artifacts/solc/src/contract.rs diff --git a/crates/artifacts/src/error.rs b/crates/artifacts/solc/src/error.rs similarity index 100% rename from crates/artifacts/src/error.rs rename to crates/artifacts/solc/src/error.rs diff --git a/crates/artifacts/src/hh.rs b/crates/artifacts/solc/src/hh.rs similarity index 100% rename from crates/artifacts/src/hh.rs rename to crates/artifacts/solc/src/hh.rs diff --git a/crates/artifacts/src/lib.rs b/crates/artifacts/solc/src/lib.rs similarity index 100% rename from crates/artifacts/src/lib.rs rename to crates/artifacts/solc/src/lib.rs diff --git a/crates/artifacts/src/output_selection.rs b/crates/artifacts/solc/src/output_selection.rs similarity index 100% rename from crates/artifacts/src/output_selection.rs rename to crates/artifacts/solc/src/output_selection.rs diff --git a/crates/artifacts/src/remappings.rs b/crates/artifacts/solc/src/remappings.rs similarity index 100% rename from crates/artifacts/src/remappings.rs rename to crates/artifacts/solc/src/remappings.rs diff --git a/crates/artifacts/src/serde_helpers.rs b/crates/artifacts/solc/src/serde_helpers.rs similarity index 100% rename from crates/artifacts/src/serde_helpers.rs rename to crates/artifacts/solc/src/serde_helpers.rs diff --git a/crates/artifacts/src/sourcemap.rs b/crates/artifacts/solc/src/sourcemap.rs similarity index 100% rename from crates/artifacts/src/sourcemap.rs rename to crates/artifacts/solc/src/sourcemap.rs diff --git a/crates/artifacts/src/sources.rs b/crates/artifacts/solc/src/sources.rs similarity index 100% rename from crates/artifacts/src/sources.rs rename to crates/artifacts/solc/src/sources.rs diff --git a/crates/artifacts-vyper/Cargo.toml b/crates/artifacts/vyper/Cargo.toml similarity index 94% rename from crates/artifacts-vyper/Cargo.toml rename to crates/artifacts/vyper/Cargo.toml index 4dec0f36..2df2295d 100644 --- a/crates/artifacts-vyper/Cargo.toml +++ b/crates/artifacts/vyper/Cargo.toml @@ -19,7 +19,7 @@ rustdoc-args = ["--cfg", "docsrs"] all-features = true [dependencies] -foundry-compilers-artifacts.workspace = true +foundry-compilers-artifacts-solc.workspace = true serde.workspace = true alloy-primitives.workspace = true diff --git a/crates/artifacts-vyper/src/error.rs b/crates/artifacts/vyper/src/error.rs similarity index 96% rename from crates/artifacts-vyper/src/error.rs rename to crates/artifacts/vyper/src/error.rs index 21b3b33d..c5c241e2 100644 --- a/crates/artifacts-vyper/src/error.rs +++ b/crates/artifacts/vyper/src/error.rs @@ -1,5 +1,5 @@ use core::fmt; -use foundry_compilers_artifacts::Severity; +use foundry_compilers_artifacts_solc::Severity; use serde::{Deserialize, Serialize}; use std::path::PathBuf; diff --git a/crates/artifacts-vyper/src/input.rs b/crates/artifacts/vyper/src/input.rs similarity index 96% rename from crates/artifacts-vyper/src/input.rs rename to crates/artifacts/vyper/src/input.rs index 7e61d015..49e8e51a 100644 --- a/crates/artifacts-vyper/src/input.rs +++ b/crates/artifacts/vyper/src/input.rs @@ -1,7 +1,7 @@ use std::path::Path; use super::VyperSettings; -use foundry_compilers_artifacts::sources::Sources; +use foundry_compilers_artifacts_solc::sources::Sources; use serde::{Deserialize, Serialize}; /// Extension of Vyper interface file. diff --git a/crates/artifacts-vyper/src/lib.rs b/crates/artifacts/vyper/src/lib.rs similarity index 100% rename from crates/artifacts-vyper/src/lib.rs rename to crates/artifacts/vyper/src/lib.rs diff --git a/crates/artifacts-vyper/src/output.rs b/crates/artifacts/vyper/src/output.rs similarity index 98% rename from crates/artifacts-vyper/src/output.rs rename to crates/artifacts/vyper/src/output.rs index 6fe04fa6..14e74b5a 100644 --- a/crates/artifacts-vyper/src/output.rs +++ b/crates/artifacts/vyper/src/output.rs @@ -1,8 +1,8 @@ use super::error::VyperCompilationError; use alloy_json_abi::JsonAbi; use alloy_primitives::Bytes; -use foundry_compilers_artifacts as solc_artifacts; -use foundry_compilers_artifacts::BytecodeObject; +use foundry_compilers_artifacts_solc as solc_artifacts; +use foundry_compilers_artifacts_solc::BytecodeObject; use serde::Deserialize; use std::{ collections::{BTreeMap, HashSet}, diff --git a/crates/artifacts-vyper/src/settings.rs b/crates/artifacts/vyper/src/settings.rs similarity index 95% rename from crates/artifacts-vyper/src/settings.rs rename to crates/artifacts/vyper/src/settings.rs index ec35250a..a0c9fa56 100644 --- a/crates/artifacts-vyper/src/settings.rs +++ b/crates/artifacts/vyper/src/settings.rs @@ -1,4 +1,6 @@ -use foundry_compilers_artifacts::{output_selection::OutputSelection, serde_helpers, EvmVersion}; +use foundry_compilers_artifacts_solc::{ + output_selection::OutputSelection, serde_helpers, EvmVersion, +}; use serde::{Deserialize, Serialize}; use std::path::Path; diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index b653ee7d..e072cc75 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -20,7 +20,6 @@ all-features = true [dependencies] foundry-compilers-artifacts.workspace = true -foundry-compilers-artifacts-vyper.workspace = true foundry-compilers-core.workspace = true serde.workspace = true semver.workspace = true diff --git a/crates/project/src/compilers/vyper/error.rs b/crates/project/src/compilers/vyper/error.rs index 63112830..91644b06 100644 --- a/crates/project/src/compilers/vyper/error.rs +++ b/crates/project/src/compilers/vyper/error.rs @@ -1,8 +1,5 @@ -use crate::compilers::CompilationError; -use crate::artifacts::vyper::VyperCompilationError; -use foundry_compilers_artifacts::{ - error::SourceLocation, Severity, -}; +use crate::{artifacts::vyper::VyperCompilationError, compilers::CompilationError}; +use foundry_compilers_artifacts::{error::SourceLocation, Severity}; impl CompilationError for VyperCompilationError { fn is_warning(&self) -> bool { diff --git a/crates/project/src/compilers/vyper/mod.rs b/crates/project/src/compilers/vyper/mod.rs index cc937d05..e997824c 100644 --- a/crates/project/src/compilers/vyper/mod.rs +++ b/crates/project/src/compilers/vyper/mod.rs @@ -1,8 +1,6 @@ use self::{input::VyperVersionedInput, parser::VyperParsedSource}; use super::{Compiler, CompilerOutput, Language}; -pub use crate::artifacts::vyper::{ - VyperCompilationError, VyperInput, VyperOutput, VyperSettings, -}; +pub use crate::artifacts::vyper::{VyperCompilationError, VyperInput, VyperOutput, VyperSettings}; use core::fmt; use foundry_compilers_artifacts::sources::Source; use foundry_compilers_core::error::{Result, SolcError}; diff --git a/crates/project/src/flatten.rs b/crates/project/src/flatten.rs index 02bffa11..c559c7a2 100644 --- a/crates/project/src/flatten.rs +++ b/crates/project/src/flatten.rs @@ -6,6 +6,7 @@ use crate::{ }; use foundry_compilers_artifacts::{ ast::{visitor::Visitor, *}, + solc::ExternalInlineAssemblyReference, sources::{Source, Sources}, ContractDefinitionPart, SourceUnit, SourceUnitPart, }; diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index 76ac902f..f27e10ed 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -47,17 +47,13 @@ pub mod report; pub mod project_util; pub use foundry_compilers_core::{error, utils}; - -pub mod artifacts { - pub use foundry_compilers_artifacts::*; - pub use foundry_compilers_artifacts_vyper as vyper; -} +pub use foundry_compilers_artifacts as artifacts; use cache::CompilerCache; use compile::output::contracts::VersionedContracts; use compilers::multi::MultiCompiler; use derivative::Derivative; -use foundry_compilers_artifacts::{ +use foundry_compilers_artifacts::solc::{ output_selection::OutputSelection, sources::{Source, Sources}, Contract, Settings, Severity, SourceFile, StandardJsonCompilerInput, From a13211cf6ef145a2491d118be4edd65953c57c66 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 14 Jun 2024 17:07:42 +0300 Subject: [PATCH 22/22] fix tests --- crates/artifacts/solc/src/ast/lowfidelity.rs | 2 +- crates/artifacts/solc/src/ast/mod.rs | 38 ++++++++++---------- crates/artifacts/solc/src/lib.rs | 12 +++---- crates/artifacts/solc/src/sourcemap.rs | 4 +-- crates/artifacts/vyper/src/output.rs | 2 +- crates/project/src/lib.rs | 2 +- 6 files changed, 31 insertions(+), 29 deletions(-) diff --git a/crates/artifacts/solc/src/ast/lowfidelity.rs b/crates/artifacts/solc/src/ast/lowfidelity.rs index db9d7f57..20ee211c 100644 --- a/crates/artifacts/solc/src/ast/lowfidelity.rs +++ b/crates/artifacts/solc/src/ast/lowfidelity.rs @@ -213,7 +213,7 @@ mod tests { #[test] fn can_parse_ast() { - let ast = include_str!("../../../../test-data/ast/ast-erc4626.json"); + let ast = include_str!("../../../../../test-data/ast/ast-erc4626.json"); let _ast: Ast = serde_json::from_str(ast).unwrap(); } } diff --git a/crates/artifacts/solc/src/ast/mod.rs b/crates/artifacts/solc/src/ast/mod.rs index 5c280ff5..45e14a3c 100644 --- a/crates/artifacts/solc/src/ast/mod.rs +++ b/crates/artifacts/solc/src/ast/mod.rs @@ -1093,24 +1093,26 @@ mod tests { #[test] fn can_parse_ast() { - fs::read_dir(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data").join("ast")) - .unwrap() - .for_each(|path| { - let path = path.unwrap().path(); - let path_str = path.to_string_lossy(); - - let input = fs::read_to_string(&path).unwrap(); - let deserializer = &mut serde_json::Deserializer::from_str(&input); - let result: Result = serde_path_to_error::deserialize(deserializer); - match result { - Err(e) => { - println!("... {path_str} fail: {e}"); - panic!(); - } - Ok(_) => { - println!("... {path_str} ok"); - } + fs::read_dir( + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../../test-data").join("ast"), + ) + .unwrap() + .for_each(|path| { + let path = path.unwrap().path(); + let path_str = path.to_string_lossy(); + + let input = fs::read_to_string(&path).unwrap(); + let deserializer = &mut serde_json::Deserializer::from_str(&input); + let result: Result = serde_path_to_error::deserialize(deserializer); + match result { + Err(e) => { + println!("... {path_str} fail: {e}"); + panic!(); } - }) + Ok(_) => { + println!("... {path_str} ok"); + } + } + }) } } diff --git a/crates/artifacts/solc/src/lib.rs b/crates/artifacts/solc/src/lib.rs index 4983a733..37f4c85c 100644 --- a/crates/artifacts/solc/src/lib.rs +++ b/crates/artifacts/solc/src/lib.rs @@ -1924,7 +1924,7 @@ mod tests { #[test] fn can_parse_compiler_output() { - let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/out"); + let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../../test-data/out"); for path in fs::read_dir(dir).unwrap() { let path = path.unwrap().path(); @@ -1937,7 +1937,7 @@ mod tests { #[test] fn can_parse_compiler_input() { - let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/in"); + let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../../test-data/in"); for path in fs::read_dir(dir).unwrap() { let path = path.unwrap().path(); @@ -1950,7 +1950,7 @@ mod tests { #[test] fn can_parse_standard_json_compiler_input() { - let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/in"); + let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../../test-data/in"); for path in fs::read_dir(dir).unwrap() { let path = path.unwrap().path(); @@ -2204,7 +2204,7 @@ mod tests { #[test] fn test_lossless_storage_layout() { - let input = include_str!("../../../test-data/foundryissue2462.json").trim(); + let input = include_str!("../../../../test-data/foundryissue2462.json").trim(); let layout: StorageLayout = serde_json::from_str(input).unwrap(); pretty_assertions::assert_eq!(input, &serde_json::to_string(&layout).unwrap()); } @@ -2212,8 +2212,8 @@ mod tests { // #[test] fn can_parse_compiler_output_spells_0_6_12() { - let path = - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../test-data/0.6.12-with-libs.json"); + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../../../test-data/0.6.12-with-libs.json"); let content = fs::read_to_string(path).unwrap(); let _output: CompilerOutput = serde_json::from_str(&content).unwrap(); } diff --git a/crates/artifacts/solc/src/sourcemap.rs b/crates/artifacts/solc/src/sourcemap.rs index 673de829..dd6e0b82 100644 --- a/crates/artifacts/solc/src/sourcemap.rs +++ b/crates/artifacts/solc/src/sourcemap.rs @@ -578,7 +578,7 @@ mod tests { #[test] fn can_parse_source_maps() { // all source maps from the compiler output test data - let source_maps = include_str!("../../../test-data/out-source-maps.txt"); + let source_maps = include_str!("../../../../test-data/out-source-maps.txt"); for (line, s) in source_maps.lines().enumerate() { parse(s).unwrap_or_else(|e| panic!("Failed to parse line {line}: {e}")); @@ -587,7 +587,7 @@ mod tests { #[test] fn can_parse_foundry_cheatcodes_sol_maps() { - let s = include_str!("../../../test-data/cheatcodes.sol-sourcemap.txt"); + let s = include_str!("../../../../test-data/cheatcodes.sol-sourcemap.txt"); let mut out = String::new(); let mut parser = Parser::new(s); parser.output = Some(&mut out); diff --git a/crates/artifacts/vyper/src/output.rs b/crates/artifacts/vyper/src/output.rs index 14e74b5a..ca9b979a 100644 --- a/crates/artifacts/vyper/src/output.rs +++ b/crates/artifacts/vyper/src/output.rs @@ -152,7 +152,7 @@ mod tests { fn test_output(artifact_path: &str) { let output = std::fs::read_to_string( - Path::new(env!("CARGO_MANIFEST_DIR")).join("../../test-data").join(artifact_path), + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../../test-data").join(artifact_path), ) .unwrap(); let output: super::VyperOutput = serde_json::from_str(&output).unwrap(); diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index f27e10ed..7a625420 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -46,8 +46,8 @@ pub mod report; #[cfg(feature = "project-util")] pub mod project_util; -pub use foundry_compilers_core::{error, utils}; pub use foundry_compilers_artifacts as artifacts; +pub use foundry_compilers_core::{error, utils}; use cache::CompilerCache; use compile::output::contracts::VersionedContracts;