fix(solc): flatten duplicates (#813)

* fix solc flatten duplicates

* upd changelog

* sample eof newlines

* fix test name

* linter
This commit is contained in:
Roman Krasiuk 2022-01-19 08:11:37 -08:00 committed by GitHub
parent eb555c28cc
commit f9b0360d90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 45 additions and 2 deletions

View File

@ -34,6 +34,8 @@
### Unreleased
- Fix duplicate files during flattening
[#813](https://github.com/gakonst/ethers-rs/pull/813)
- Add ability to flatten file imports
[#774](https://github.com/gakonst/ethers-rs/pull/774)
- Add dependency graph and resolve all imported libraryfiles

View File

@ -176,7 +176,7 @@ impl ProjectPathsConfig {
pub fn flatten(&self, target: &Path) -> Result<String> {
tracing::trace!("flattening file");
let graph = Graph::resolve(self)?;
self.flatten_node(target, &graph, false, false)
self.flatten_node(target, &graph, &mut vec![], false, false)
}
/// Flattens a single node from the dependency graph
@ -184,6 +184,7 @@ impl ProjectPathsConfig {
&self,
target: &Path,
graph: &Graph,
imported: &mut Vec<usize>,
strip_version_pragma: bool,
strip_license: bool,
) -> Result<String> {
@ -193,6 +194,11 @@ impl ProjectPathsConfig {
let target_index = graph.files().get(target).ok_or_else(|| {
SolcError::msg(format!("cannot resolve file at \"{:?}\"", target.display()))
})?;
if imported.iter().any(|&idx| idx == *target_index) {
return Ok(String::new())
}
let target_node = graph.node(*target_index);
let mut imports = target_node.imports().clone();
@ -219,7 +225,7 @@ impl ProjectPathsConfig {
for import in imports.iter() {
let import_path = self.resolve_import(target_dir, import.data())?;
let import_content = self.flatten_node(&import_path, graph, true, true)?;
let import_content = self.flatten_node(&import_path, graph, imported, true, true)?;
let import_content = import_content.trim().as_bytes().to_owned();
let import_content_len = import_content.len() as isize;
let (start, end) = import.loc_by_offset(offset);
@ -230,6 +236,7 @@ impl ProjectPathsConfig {
let result = String::from_utf8(content).map_err(|err| {
SolcError::msg(format!("failed to convert extended bytes to string: {}", err))
})?;
imported.push(*target_index);
Ok(result)
}

View File

@ -0,0 +1,4 @@
//SPDX-License-Identifier: Unlicense
pragma solidity >=0.6.0;
contract Bar {}

View File

@ -0,0 +1,6 @@
//SPDX-License-Identifier: Unlicense
pragma solidity >=0.6.0;
import { Bar } from './Bar.sol';
contract Foo {}

View File

@ -0,0 +1,7 @@
//SPDX-License-Identifier: Unlicense
pragma solidity >=0.6.0;
import { Bar } from './Bar.sol';
import { Foo } from './Foo.sol';
contract FooBar {}

View File

@ -360,3 +360,20 @@ fn can_flatten_file_in_dapp_sample() {
assert!(result.find("contract Dapp").is_some());
assert!(result.find("contract DappTest").is_some());
}
#[test]
fn can_flatten_file_with_duplicates() {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/flatten-sample");
let paths = ProjectPathsConfig::builder().sources(root.join("contracts"));
let project = TempProject::<MinimalCombinedArtifacts>::new(paths).unwrap();
let target = root.join("contracts/FooBar.sol");
let result = project.flatten(&target);
assert!(result.is_ok());
let result = result.unwrap();
assert!(result.matches("contract Foo {").collect::<Vec<_>>().len() == 1);
assert!(result.matches("contract Bar {").collect::<Vec<_>>().len() == 1);
assert!(result.matches("contract FooBar {").collect::<Vec<_>>().len() == 1);
}