From 1f822e47e6ec046c3c5563d18116265dd69f2e2e Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Tue, 22 Feb 2022 06:22:24 -0800 Subject: [PATCH] fix(solc): flatten import loc (#946) * protograva test-data * revert import parsing change * compare flatten results against full strings --- ethers-solc/src/config.rs | 7 ++- ethers-solc/src/resolver/mod.rs | 10 ++-- .../contracts/Bar.sol | 2 +- .../contracts/Foo.sol | 2 +- .../contracts/FooBar.sol | 2 +- .../contracts/Contract.sol | 9 ++++ .../contracts/Lib.sol | 4 ++ ethers-solc/tests/project.rs | 47 +++++++++++++++++-- 8 files changed, 70 insertions(+), 13 deletions(-) rename ethers-solc/test-data/{flatten-sample => test-flatten-duplicates}/contracts/Bar.sol (52%) rename ethers-solc/test-data/{flatten-sample => test-flatten-duplicates}/contracts/Foo.sol (66%) rename ethers-solc/test-data/{flatten-sample => test-flatten-duplicates}/contracts/FooBar.sol (74%) create mode 100644 ethers-solc/test-data/test-flatten-solang-failure/contracts/Contract.sol create mode 100644 ethers-solc/test-data/test-flatten-solang-failure/contracts/Lib.sol diff --git a/ethers-solc/src/config.rs b/ethers-solc/src/config.rs index 9a7077b5..bff8bdea 100644 --- a/ethers-solc/src/config.rs +++ b/ethers-solc/src/config.rs @@ -278,8 +278,11 @@ 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, imported, true, true)?; - let import_content = import_content.trim().as_bytes().to_owned(); + let import_content = self + .flatten_node(&import_path, graph, imported, true, true)? + .trim() + .as_bytes() + .to_owned(); let import_content_len = import_content.len() as isize; let (start, end) = import.loc_by_offset(offset); content.splice(start..end, import_content); diff --git a/ethers-solc/src/resolver/mod.rs b/ethers-solc/src/resolver/mod.rs index c8e1ca60..104865fd 100644 --- a/ethers-solc/src/resolver/mod.rs +++ b/ethers-solc/src/resolver/mod.rs @@ -807,9 +807,13 @@ fn parse_data(content: &str, file: &Path) -> SolData { .map(|(cap, name)| { SolDataUnit::new(name.as_str().to_owned(), cap.to_owned().into()) }); - imports = utils::find_import_paths(content) - .map(|m| SolDataUnit::new(PathBuf::from(m.as_str()), m.to_owned().into())) - .collect(); + imports = + capture_outer_and_inner(content, &utils::RE_SOL_IMPORT, &["p1", "p2", "p3", "p4"]) + .iter() + .map(|(cap, m)| { + SolDataUnit::new(PathBuf::from(m.as_str()), cap.to_owned().into()) + }) + .collect(); } }; let license = content.lines().next().and_then(|line| { diff --git a/ethers-solc/test-data/flatten-sample/contracts/Bar.sol b/ethers-solc/test-data/test-flatten-duplicates/contracts/Bar.sol similarity index 52% rename from ethers-solc/test-data/flatten-sample/contracts/Bar.sol rename to ethers-solc/test-data/test-flatten-duplicates/contracts/Bar.sol index 5cb19aba..5e9034a5 100644 --- a/ethers-solc/test-data/flatten-sample/contracts/Bar.sol +++ b/ethers-solc/test-data/test-flatten-duplicates/contracts/Bar.sol @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: Unlicense +//SPDX-License-Identifier: UNLICENSED pragma solidity >=0.6.0; contract Bar {} diff --git a/ethers-solc/test-data/flatten-sample/contracts/Foo.sol b/ethers-solc/test-data/test-flatten-duplicates/contracts/Foo.sol similarity index 66% rename from ethers-solc/test-data/flatten-sample/contracts/Foo.sol rename to ethers-solc/test-data/test-flatten-duplicates/contracts/Foo.sol index f9cf562d..1f7086de 100644 --- a/ethers-solc/test-data/flatten-sample/contracts/Foo.sol +++ b/ethers-solc/test-data/test-flatten-duplicates/contracts/Foo.sol @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: Unlicense +//SPDX-License-Identifier: UNLICENSED pragma solidity >=0.6.0; import { Bar } from './Bar.sol'; diff --git a/ethers-solc/test-data/flatten-sample/contracts/FooBar.sol b/ethers-solc/test-data/test-flatten-duplicates/contracts/FooBar.sol similarity index 74% rename from ethers-solc/test-data/flatten-sample/contracts/FooBar.sol rename to ethers-solc/test-data/test-flatten-duplicates/contracts/FooBar.sol index eda3b10b..58ec146b 100644 --- a/ethers-solc/test-data/flatten-sample/contracts/FooBar.sol +++ b/ethers-solc/test-data/test-flatten-duplicates/contracts/FooBar.sol @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: Unlicense +//SPDX-License-Identifier: UNLICENSED pragma solidity >=0.6.0; import { Bar } from './Bar.sol'; diff --git a/ethers-solc/test-data/test-flatten-solang-failure/contracts/Contract.sol b/ethers-solc/test-data/test-flatten-solang-failure/contracts/Contract.sol new file mode 100644 index 00000000..c0be0077 --- /dev/null +++ b/ethers-solc/test-data/test-flatten-solang-failure/contracts/Contract.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.10; + +import { Lib } from "./Lib.sol"; + +// Intentionally erroneous code +contract Contract { + failure(); +} diff --git a/ethers-solc/test-data/test-flatten-solang-failure/contracts/Lib.sol b/ethers-solc/test-data/test-flatten-solang-failure/contracts/Lib.sol new file mode 100644 index 00000000..407fb855 --- /dev/null +++ b/ethers-solc/test-data/test-flatten-solang-failure/contracts/Lib.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.10; + +library Lib {} diff --git a/ethers-solc/tests/project.rs b/ethers-solc/tests/project.rs index 2a32d16f..f3c7ab46 100644 --- a/ethers-solc/tests/project.rs +++ b/ethers-solc/tests/project.rs @@ -375,6 +375,7 @@ fn can_flatten_file() { assert!(result.is_ok()); let result = result.unwrap(); + assert!(!result.contains("import")); assert!(result.contains("contract Foo")); assert!(result.contains("contract Bar")); } @@ -393,6 +394,7 @@ fn can_flatten_file_with_external_lib() { assert!(result.is_ok()); let result = result.unwrap(); + assert!(!result.contains("import")); assert!(result.contains("library console")); assert!(result.contains("contract Greeter")); } @@ -409,6 +411,7 @@ fn can_flatten_file_in_dapp_sample() { assert!(result.is_ok()); let result = result.unwrap(); + assert!(!result.contains("import")); assert!(result.contains("contract DSTest")); assert!(result.contains("contract Dapp")); assert!(result.contains("contract DappTest")); @@ -416,7 +419,7 @@ fn can_flatten_file_in_dapp_sample() { #[test] fn can_flatten_file_with_duplicates() { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/flatten-sample"); + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/test-flatten-duplicates"); let paths = ProjectPathsConfig::builder().sources(root.join("contracts")); let project = TempProject::::new(paths).unwrap(); @@ -426,10 +429,44 @@ fn can_flatten_file_with_duplicates() { assert!(result.is_ok()); let result = result.unwrap(); - assert_eq!(result.matches("contract Foo {").count(), 1); - assert_eq!(result.matches("contract Bar {").count(), 1); - assert_eq!(result.matches("contract FooBar {").count(), 1); - assert_eq!(result.matches(';').count(), 1); + assert_eq!( + result, + r#"//SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.0; + +contract Bar {} +contract Foo {} + +contract FooBar {} +"# + ); +} + +#[test] +fn can_flatten_on_solang_failure() { + let root = + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/test-flatten-solang-failure"); + let paths = ProjectPathsConfig::builder().sources(&root.join("contracts")); + let project = TempProject::::new(paths).unwrap(); + + let target = root.join("contracts/Contract.sol"); + + let result = project.flatten(&target); + assert!(result.is_ok()); + + let result = result.unwrap(); + assert_eq!( + result, + r#"// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.10; + +library Lib {} +// Intentionally erroneous code +contract Contract { + failure(); +} +"# + ); } #[test]