Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

fix(solc): flatten duplicates #813

Merged
merged 5 commits into from
Jan 19, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 9 additions & 2 deletions ethers-solc/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,15 @@ 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
fn flatten_node(
&self,
target: &Path,
graph: &Graph,
imported: &mut Vec<usize>,
strip_version_pragma: bool,
strip_license: bool,
) -> Result<String> {
Expand All @@ -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().find(|&&idx| idx == *target_index).is_some() {
return Ok(String::new())
}

let target_node = graph.node(*target_index);

let mut imports = target_node.imports().clone();
Expand All @@ -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);
Expand All @@ -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)
}
Expand Down
4 changes: 4 additions & 0 deletions ethers-solc/test-data/flatten-sample/contracts/Bar.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//SPDX-License-Identifier: Unlicense
pragma solidity >=0.6.0;

contract Bar {}
6 changes: 6 additions & 0 deletions ethers-solc/test-data/flatten-sample/contracts/Foo.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//SPDX-License-Identifier: Unlicense
pragma solidity >=0.6.0;

import { Bar } from './Bar.sol';

contract Foo {}
7 changes: 7 additions & 0 deletions ethers-solc/test-data/flatten-sample/contracts/FooBar.sol
Original file line number Diff line number Diff line change
@@ -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 {}
17 changes: 17 additions & 0 deletions ethers-solc/tests/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_without_duplicates() {
rkrasiuk marked this conversation as resolved.
Show resolved Hide resolved
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);
}