Skip to content

Commit 21b69ff

Browse files
authored
chore(evm): re-use project output in SourceData (#11541)
1 parent 02f07d4 commit 21b69ff

File tree

7 files changed

+57
-48
lines changed

7 files changed

+57
-48
lines changed

crates/cast/src/cmd/storage.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -150,21 +150,23 @@ impl StorageArgs {
150150
eyre::bail!("Contract at provided address is not a valid Solidity contract")
151151
}
152152

153-
let version = metadata.compiler_version()?;
154-
let auto_detect = version < MIN_SOLC;
155-
156153
// Create a new temp project
157154
// TODO: Cache instead of using a temp directory: metadata from Etherscan won't change
158155
let root = tempfile::tempdir()?;
159156
let root_path = root.path();
160157
let mut project = etherscan_project(metadata, root_path)?;
161158
add_storage_layout_output(&mut project);
162159

163-
project.compiler = if auto_detect {
164-
SolcCompiler::AutoDetect
165-
} else {
166-
SolcCompiler::Specific(Solc::find_or_install(&version)?)
167-
};
160+
let mut version = metadata.compiler_version()?;
161+
let mut auto_detect = false;
162+
if let Some(solcc) = project.compiler.solc.as_mut()
163+
&& let SolcCompiler::Specific(solc) = solcc
164+
&& solc.version < MIN_SOLC
165+
{
166+
version = solc.version.clone();
167+
*solcc = SolcCompiler::AutoDetect;
168+
auto_detect = true;
169+
}
168170

169171
// Compile
170172
let mut out = ProjectCompiler::new().quiet(true).compile(&project)?;
@@ -174,13 +176,14 @@ impl StorageArgs {
174176
.find(|(name, _)| name == &metadata.contract_name)
175177
.ok_or_else(|| eyre::eyre!("Could not find artifact"))?;
176178

177-
if is_storage_layout_empty(&artifact.storage_layout) && auto_detect {
179+
if auto_detect && is_storage_layout_empty(&artifact.storage_layout) {
178180
// try recompiling with the minimum version
179181
sh_warn!(
180-
"The requested contract was compiled with {version} while the minimum version for storage layouts is {MIN_SOLC} and as a result the output may be empty."
182+
"The requested contract was compiled with {version} while the minimum version \
183+
for storage layouts is {MIN_SOLC} and as a result the output may be empty.",
181184
)?;
182185
let solc = Solc::find_or_install(&MIN_SOLC)?;
183-
project.compiler = SolcCompiler::Specific(solc);
186+
project.compiler.solc = Some(SolcCompiler::Specific(solc));
184187
if let Ok(output) = ProjectCompiler::new().quiet(true).compile(&project) {
185188
out = output;
186189
let (_, new_artifact) = out

crates/chisel/src/source.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use foundry_evm::{backend::Backend, opts::EvmOpts};
1818
use semver::Version;
1919
use serde::{Deserialize, Serialize};
2020
use solang_parser::pt;
21-
use solar::parse::interface::diagnostics::EmittedDiagnostics;
21+
use solar::interface::diagnostics::EmittedDiagnostics;
2222
use std::{cell::OnceCell, collections::HashMap, fmt, path::PathBuf};
2323
use walkdir::WalkDir;
2424

crates/common/src/compile.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use foundry_compilers::{
1414
solc::{Solc, SolcCompiler},
1515
},
1616
info::ContractInfo as CompilerContractInfo,
17+
multi::{MultiCompiler, MultiCompilerSettings},
1718
project::Preprocessor,
1819
report::{BasicStdoutReporter, NoReporter, Report},
1920
solc::SolcSettings,
@@ -519,11 +520,8 @@ where
519520
}
520521

521522
/// Creates a [Project] from an Etherscan source.
522-
pub fn etherscan_project(
523-
metadata: &Metadata,
524-
target_path: impl AsRef<Path>,
525-
) -> Result<Project<SolcCompiler>> {
526-
let target_path = dunce::canonicalize(target_path.as_ref())?;
523+
pub fn etherscan_project(metadata: &Metadata, target_path: &Path) -> Result<Project> {
524+
let target_path = dunce::canonicalize(target_path)?;
527525
let sources_path = target_path.join(&metadata.contract_name);
528526
metadata.source_tree().write_to(&target_path)?;
529527

@@ -553,14 +551,18 @@ pub fn etherscan_project(
553551
.remappings(settings.remappings.clone())
554552
.build_with_root(sources_path);
555553

554+
// TODO: detect vyper
556555
let v = metadata.compiler_version()?;
557556
let solc = Solc::find_or_install(&v)?;
558557

559-
let compiler = SolcCompiler::Specific(solc);
558+
let compiler = MultiCompiler { solc: Some(SolcCompiler::Specific(solc)), vyper: None };
560559

561-
Ok(ProjectBuilder::<SolcCompiler>::default()
562-
.settings(SolcSettings {
563-
settings: SolcConfig::builder().settings(settings).build(),
560+
Ok(ProjectBuilder::<MultiCompiler>::default()
561+
.settings(MultiCompilerSettings {
562+
solc: SolcSettings {
563+
settings: SolcConfig::builder().settings(settings).build(),
564+
..Default::default()
565+
},
564566
..Default::default()
565567
})
566568
.paths(paths)

crates/common/src/preprocessor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl Preprocessor<SolcCompiler> for DynamicTestLinkingPreprocessor {
5252
let mut compiler =
5353
foundry_compilers::resolver::parse::SolParser::new(paths.with_language_ref())
5454
.into_compiler();
55-
let _ = compiler.enter_mut(|compiler| -> solar::parse::interface::Result {
55+
let _ = compiler.enter_mut(|compiler| -> solar::interface::Result {
5656
let mut pcx = compiler.parse();
5757

5858
// Add the sources into the context.

crates/config/src/inline/natspec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use foundry_compilers::{
66
};
77
use itertools::Itertools;
88
use serde_json::Value;
9-
use solar::parse::ast;
9+
use solar::ast;
1010
use std::{collections::BTreeMap, path::Path};
1111

1212
/// Convenient struct to hold in-line per-test configurations

crates/evm/traces/src/debug/sources.rs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
use eyre::{Context, Result};
22
use foundry_common::{compact_to_contract, strip_bytecode_placeholders};
33
use foundry_compilers::{
4-
Artifact, Compiler, ProjectCompileOutput,
4+
Artifact, ProjectCompileOutput,
55
artifacts::{
6-
Bytecode, Contract, ContractBytecodeSome, Libraries, Source,
6+
Bytecode, ContractBytecodeSome, Libraries, Source,
77
sourcemap::{SourceElement, SourceMap},
88
},
99
multi::MultiCompilerLanguage,
1010
};
1111
use foundry_evm_core::ic::PcIcMap;
1212
use foundry_linking::Linker;
1313
use rayon::prelude::*;
14-
use solar::parse::{Parser, interface::Session};
1514
use std::{
1615
collections::{BTreeMap, HashMap, HashSet},
1716
fmt::Write,
@@ -31,7 +30,13 @@ pub struct SourceData {
3130
}
3231

3332
impl SourceData {
34-
pub fn new(source: Arc<String>, language: MultiCompilerLanguage, path: PathBuf) -> Self {
33+
pub fn new(
34+
output: &ProjectCompileOutput,
35+
source: Arc<String>,
36+
language: MultiCompilerLanguage,
37+
path: PathBuf,
38+
root: &Path,
39+
) -> Self {
3540
let mut contract_definitions = Vec::new();
3641

3742
match language {
@@ -42,21 +47,21 @@ impl SourceData {
4247
}
4348
}
4449
MultiCompilerLanguage::Solc(_) => {
45-
let sess = Session::builder().with_silent_emitter(None).build();
46-
let _ = sess.enter(|| -> solar::parse::interface::Result<()> {
47-
let arena = solar::parse::ast::Arena::new();
48-
let filename = path.clone().into();
49-
let mut parser =
50-
Parser::from_source_code(&sess, &arena, filename, source.to_string())?;
51-
let ast = parser.parse_file().map_err(|e| e.emit())?;
52-
for item in ast.items {
53-
if let solar::parse::ast::ItemKind::Contract(contract) = &item.kind {
54-
let range = item.span.lo().to_usize()..item.span.hi().to_usize();
55-
contract_definitions.push((contract.name.to_string(), range));
50+
let r = output.parser().solc().compiler().enter(|compiler| -> Option<()> {
51+
let (_, source) = compiler.gcx().get_ast_source(root.join(&path))?;
52+
for item in source.ast.as_ref()?.items.iter() {
53+
if let solar::ast::ItemKind::Contract(contract) = &item.kind {
54+
contract_definitions.push((
55+
contract.name.to_string(),
56+
compiler.sess().source_map().span_to_source(item.span).unwrap().1,
57+
));
5658
}
5759
}
58-
Ok(())
60+
Some(())
5961
});
62+
if r.is_none() {
63+
warn!("failed to parse contract definitions for {}", path.display());
64+
}
6065
}
6166
}
6267

@@ -135,15 +140,12 @@ impl ContractSources {
135140
Ok(sources)
136141
}
137142

138-
pub fn insert<C: Compiler<CompilerContract = Contract>>(
143+
pub fn insert(
139144
&mut self,
140-
output: &ProjectCompileOutput<C>,
145+
output: &ProjectCompileOutput,
141146
root: &Path,
142147
libraries: Option<&Libraries>,
143-
) -> Result<()>
144-
where
145-
C::Language: Into<MultiCompilerLanguage>,
146-
{
148+
) -> Result<()> {
147149
let link_data = libraries.map(|libraries| {
148150
let linker = Linker::new(root, output.artifact_ids().collect());
149151
(linker, libraries)
@@ -197,9 +199,11 @@ impl ContractSources {
197199
})?;
198200
let stripped = path.strip_prefix(root).unwrap_or(path).to_path_buf();
199201
let source_data = Arc::new(SourceData::new(
202+
output,
200203
source.content.clone(),
201-
build.language.into(),
204+
build.language,
202205
stripped,
206+
root,
203207
));
204208
entry.insert(source_data.clone());
205209
source_data

crates/forge/src/cmd/bind_json.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl BindJsonArgs {
103103
/// in most of the cases.
104104
fn preprocess_sources(&self, sources: &mut Sources) -> Result<()> {
105105
let sess = Session::builder().with_stderr_emitter().build();
106-
let result = sess.enter(|| -> solar::parse::interface::Result<()> {
106+
let result = sess.enter(|| -> solar::interface::Result<()> {
107107
sources.0.par_iter_mut().try_for_each(|(path, source)| {
108108
let mut content = Arc::try_unwrap(std::mem::take(&mut source.content)).unwrap();
109109

@@ -426,7 +426,7 @@ impl PreprocessorVisitor {
426426
}
427427

428428
impl<'ast> Visit<'ast> for PreprocessorVisitor {
429-
type BreakValue = solar::parse::interface::data_structures::Never;
429+
type BreakValue = solar::interface::data_structures::Never;
430430

431431
fn visit_item_function(
432432
&mut self,

0 commit comments

Comments
 (0)