Skip to content

Commit ed443d7

Browse files
grandizzyzerosnacks
authored andcommitted
fix(remappings): ignore remappings of root proj dirs when merging (foundry-rs#9258)
* fix(remappings): ignore remappings of root proj dir when merging * Remove unused code * Add test * Update * Load project paths from figment --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
1 parent 46f3946 commit ed443d7

File tree

4 files changed

+78
-25
lines changed

4 files changed

+78
-25
lines changed

crates/cli/src/opts/build/core.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ impl<'a> From<&'a CoreBuildArgs> for Figment {
181181
};
182182

183183
// remappings should stack
184-
let mut remappings = Remappings::new_with_remappings(args.project_paths.get_remappings());
184+
let mut remappings = Remappings::new_with_remappings(args.project_paths.get_remappings())
185+
.with_figment(&figment);
185186
remappings
186187
.extend(figment.extract_inner::<Vec<Remapping>>("remappings").unwrap_or_default());
187188
figment = figment.merge(("remappings", remappings.into_inner())).merge(args);

crates/config/src/lib.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,23 +1091,6 @@ impl Config {
10911091
}
10921092

10931093
/// Returns all configured remappings.
1094-
///
1095-
/// **Note:** this will add an additional `<src>/=<src path>` remapping here, see
1096-
/// [Self::get_source_dir_remapping()]
1097-
///
1098-
/// So that
1099-
///
1100-
/// ```solidity
1101-
/// import "./math/math.sol";
1102-
/// import "contracts/tokens/token.sol";
1103-
/// ```
1104-
///
1105-
/// in `contracts/contract.sol` are resolved to
1106-
///
1107-
/// ```text
1108-
/// contracts/tokens/token.sol
1109-
/// contracts/math/math.sol
1110-
/// ```
11111094
pub fn get_all_remappings(&self) -> impl Iterator<Item = Remapping> + '_ {
11121095
self.remappings.iter().map(|m| m.clone().into())
11131096
}

crates/config/src/providers/remappings.rs

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
use crate::{foundry_toml_dirs, remappings_from_env_var, remappings_from_newline, Config};
1+
use crate::{
2+
foundry_toml_dirs, remappings_from_env_var, remappings_from_newline, utils::get_dir_remapping,
3+
Config,
4+
};
25
use figment::{
36
value::{Dict, Map},
4-
Error, Metadata, Profile, Provider,
7+
Error, Figment, Metadata, Profile, Provider,
58
};
69
use foundry_compilers::artifacts::remappings::{RelativeRemapping, Remapping};
710
use std::{
@@ -16,17 +19,35 @@ use std::{
1619
pub struct Remappings {
1720
/// Remappings.
1821
remappings: Vec<Remapping>,
22+
/// Source, test and script configured project dirs.
23+
/// Remappings of these dirs from libs are ignored.
24+
project_paths: Vec<Remapping>,
1925
}
2026

2127
impl Remappings {
2228
/// Create a new `Remappings` wrapper with an empty vector.
2329
pub fn new() -> Self {
24-
Self { remappings: Vec::new() }
30+
Self { remappings: Vec::new(), project_paths: Vec::new() }
2531
}
2632

2733
/// Create a new `Remappings` wrapper with a vector of remappings.
2834
pub fn new_with_remappings(remappings: Vec<Remapping>) -> Self {
29-
Self { remappings }
35+
Self { remappings, project_paths: Vec::new() }
36+
}
37+
38+
/// Extract project paths that cannot be remapped by dependencies.
39+
pub fn with_figment(mut self, figment: &Figment) -> Self {
40+
let mut add_project_remapping = |path: &str| {
41+
if let Ok(path) = figment.find_value(path) {
42+
if let Some(remapping) = path.into_string().and_then(get_dir_remapping) {
43+
self.project_paths.push(remapping);
44+
}
45+
}
46+
};
47+
add_project_remapping("src");
48+
add_project_remapping("test");
49+
add_project_remapping("script");
50+
self
3051
}
3152

3253
/// Filters the remappings vector by name and context.
@@ -47,16 +68,28 @@ impl Remappings {
4768

4869
/// Push an element to the remappings vector, but only if it's not already present.
4970
pub fn push(&mut self, remapping: Remapping) {
50-
if !self.remappings.iter().any(|existing| {
71+
if self.remappings.iter().any(|existing| {
5172
// What we're doing here is filtering for ambiguous paths. For example, if we have
5273
// @prb/math/=node_modules/@prb/math/src/ as existing, and
5374
// @prb/=node_modules/@prb/ as the one being checked,
5475
// we want to keep the already existing one, which is the first one. This way we avoid
5576
// having to deal with ambiguous paths which is unwanted when autodetecting remappings.
5677
existing.name.starts_with(&remapping.name) && existing.context == remapping.context
5778
}) {
58-
self.remappings.push(remapping)
59-
}
79+
return;
80+
};
81+
82+
// Ignore remappings of root project src, test or script dir.
83+
// See <https://github.com/foundry-rs/foundry/issues/3440>.
84+
if self
85+
.project_paths
86+
.iter()
87+
.any(|project_path| remapping.name.eq_ignore_ascii_case(&project_path.name))
88+
{
89+
return;
90+
};
91+
92+
self.remappings.push(remapping);
6093
}
6194

6295
/// Extend the remappings vector, leaving out the remappings that are already present.

crates/forge/tests/cli/config.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,3 +777,39 @@ forgetest!(normalize_config_evm_version, |_prj, cmd| {
777777
let config: Config = serde_json::from_str(&output).unwrap();
778778
assert_eq!(config.evm_version, EvmVersion::Istanbul);
779779
});
780+
781+
// Tests that root paths are properly resolved even if submodule specifies remappings for them.
782+
// See <https://github.com/foundry-rs/foundry/issues/3440>
783+
forgetest_init!(test_submodule_root_path_remappings, |prj, cmd| {
784+
prj.add_script(
785+
"BaseScript.sol",
786+
r#"
787+
import "forge-std/Script.sol";
788+
789+
contract BaseScript is Script {
790+
}
791+
"#,
792+
)
793+
.unwrap();
794+
prj.add_script(
795+
"MyScript.sol",
796+
r#"
797+
import "script/BaseScript.sol";
798+
799+
contract MyScript is BaseScript {
800+
}
801+
"#,
802+
)
803+
.unwrap();
804+
805+
let nested = prj.paths().libraries[0].join("another-dep");
806+
pretty_err(&nested, fs::create_dir_all(&nested));
807+
let mut lib_config = Config::load_with_root(&nested);
808+
lib_config.remappings = vec![
809+
Remapping::from_str("test/=test/").unwrap().into(),
810+
Remapping::from_str("script/=script/").unwrap().into(),
811+
];
812+
let lib_toml_file = nested.join("foundry.toml");
813+
pretty_err(&lib_toml_file, fs::write(&lib_toml_file, lib_config.to_string_pretty().unwrap()));
814+
cmd.forge_fuse().args(["build"]).assert_success();
815+
});

0 commit comments

Comments
 (0)