Skip to content

Commit 594c09b

Browse files
committed
Changes after review
1 parent 0f78197 commit 594c09b

File tree

2 files changed

+88
-34
lines changed

2 files changed

+88
-34
lines changed

crates/compilers/src/lib.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ use semver::Version;
6464
use solc::SolcSettings;
6565
use std::{
6666
collections::{BTreeMap, HashMap, HashSet},
67+
ops::Range,
6768
path::{Path, PathBuf},
6869
};
6970

@@ -884,6 +885,23 @@ fn rebase_path(base: &Path, path: &Path) -> PathBuf {
884885
new_path.to_slash_lossy().into_owned().into()
885886
}
886887

888+
/// Utility function to change source content ranges with provided updates.
889+
fn replace_source_content<'a>(
890+
source: &str,
891+
updates: impl Iterator<Item = (Range<usize>, &'a str)>,
892+
) -> String {
893+
let mut updated_content = source.to_string();
894+
let mut offset = 0;
895+
for (range, update) in updates {
896+
let start = range.start - offset;
897+
let end = range.end - offset;
898+
899+
updated_content.replace_range(start..end, update);
900+
offset += end - start;
901+
}
902+
updated_content
903+
}
904+
887905
#[cfg(test)]
888906
#[cfg(feature = "svm-solc")]
889907
mod tests {
@@ -1033,4 +1051,54 @@ mod tests {
10331051
.unwrap();
10341052
assert!(resolved.exists());
10351053
}
1054+
1055+
#[test]
1056+
fn test_replace_source_content() {
1057+
let original_content = r#"
1058+
library Lib {
1059+
function libFn() internal {
1060+
// logic to keep
1061+
}
1062+
}
1063+
contract A {
1064+
function a() external {}
1065+
function b() public {}
1066+
function c() internal {
1067+
// logic logic logic
1068+
}
1069+
function d() private {}
1070+
function e() external {
1071+
// logic logic logic
1072+
}
1073+
}"#;
1074+
let updates = vec![
1075+
// Replace function libFn() visibility to external
1076+
((36..44), "external"),
1077+
// Replace contract A name to contract B
1078+
((88..98), "contract B"),
1079+
// Remove function c()
1080+
((167..230), ""),
1081+
// Replace function e() logic
1082+
((294..314), "// no logic"),
1083+
]
1084+
.into_iter();
1085+
1086+
assert_eq!(
1087+
replace_source_content(original_content, updates),
1088+
r#"
1089+
library Lib {
1090+
function libFn() external {
1091+
// logic to keep
1092+
}
1093+
}
1094+
contract B {
1095+
function a() external {}
1096+
function b() public {}
1097+
function d() private {}
1098+
function e() external {
1099+
// no logic
1100+
}
1101+
}"#
1102+
);
1103+
}
10361104
}

crates/compilers/src/preprocessor.rs

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::project::Preprocessor;
22
use crate::{
33
flatten::{apply_updates, Updates},
44
multi::{MultiCompiler, MultiCompilerInput, MultiCompilerLanguage},
5+
replace_source_content,
56
solc::{SolcCompiler, SolcVersionedInput},
67
Compiler, ProjectPathsConfig, Result, SolcError,
78
};
@@ -10,15 +11,15 @@ use foundry_compilers_artifacts::{
1011
ast::SourceLocation,
1112
output_selection::OutputSelection,
1213
visitor::{Visitor, Walk},
13-
ContractDefinitionPart, Expression, FunctionCall, FunctionKind, MemberAccess, NewExpression,
14-
ParameterList, SolcLanguage, Source, SourceUnit, SourceUnitPart, Sources, TypeName,
14+
ContractDefinitionPart, Expression, FunctionCall, MemberAccess, NewExpression, ParameterList,
15+
SolcLanguage, Source, SourceUnit, SourceUnitPart, Sources, TypeName,
1516
};
1617
use foundry_compilers_core::utils;
1718
use itertools::Itertools;
1819
use md5::Digest;
1920
use solar_parse::{
20-
ast::{Span, Visibility},
21-
interface::diagnostics::EmittedDiagnostics,
21+
ast::{Arena, FunctionKind, ItemKind, Span, Visibility},
22+
interface::{diagnostics::EmittedDiagnostics, source_map::FileName},
2223
};
2324
use std::{
2425
collections::{BTreeMap, BTreeSet},
@@ -38,34 +39,30 @@ pub(crate) fn interface_representation(
3839
let sess =
3940
solar_parse::interface::Session::builder().with_buffer_emitter(Default::default()).build();
4041
sess.enter(|| {
41-
let arena = solar_parse::ast::Arena::new();
42-
let filename = solar_parse::interface::source_map::FileName::Real(file.to_path_buf());
42+
let arena = Arena::new();
43+
let filename = FileName::Real(file.to_path_buf());
4344
let Ok(mut parser) =
4445
solar_parse::Parser::from_source_code(&sess, &arena, filename, content.to_string())
4546
else {
4647
return;
4748
};
4849
let Ok(ast) = parser.parse_file().map_err(|e| e.emit()) else { return };
4950
for item in ast.items {
50-
if let solar_parse::ast::ItemKind::Contract(contract) = &item.kind {
51+
if let ItemKind::Contract(contract) = &item.kind {
5152
if contract.kind.is_interface() | contract.kind.is_library() {
5253
continue;
5354
}
5455
for contract_item in contract.body.iter() {
55-
if let solar_parse::ast::ItemKind::Function(function) = &contract_item.kind {
56+
if let ItemKind::Function(function) = &contract_item.kind {
5657
let is_exposed = match function.kind {
5758
// Function with external or public visibility
58-
solar_parse::ast::FunctionKind::Function => {
59-
function.header.visibility.is_some_and(|visibility| {
60-
visibility == Visibility::External
61-
|| visibility == Visibility::Public
62-
})
59+
FunctionKind::Function => {
60+
function.header.visibility >= Some(Visibility::Public)
6361
}
64-
solar_parse::ast::FunctionKind::Constructor
65-
| solar_parse::ast::FunctionKind::Fallback
66-
| solar_parse::ast::FunctionKind::Receive => true,
67-
// Other (modifiers)
68-
_ => false,
62+
FunctionKind::Constructor
63+
| FunctionKind::Fallback
64+
| FunctionKind::Receive => true,
65+
FunctionKind::Modifier => false,
6966
};
7067

7168
// If function is not exposed we remove the entire span (signature and
@@ -84,24 +81,13 @@ pub(crate) fn interface_representation(
8481

8582
// Return if any diagnostics emitted during content parsing.
8683
if let Err(err) = sess.emitted_errors().unwrap() {
87-
let e = err.to_string();
88-
trace!("failed parsing {file:?}: {e}");
84+
trace!("failed parsing {file:?}: {err}");
8985
return Err(err);
9086
}
9187

92-
let mut content = content.to_string();
93-
let mut offset = 0;
94-
95-
for span in spans_to_remove {
96-
let range = span.to_range();
97-
let start = range.start - offset;
98-
let end = range.end - offset;
99-
100-
content.replace_range(start..end, "");
101-
offset += end - start;
102-
}
103-
104-
let content = content.replace("\n", "");
88+
let content =
89+
replace_source_content(content, spans_to_remove.iter().map(|span| (span.to_range(), "")))
90+
.replace("\n", "");
10591
Ok(utils::RE_TWO_OR_MORE_SPACES.replace_all(&content, "").to_string())
10692
}
10793

@@ -391,7 +377,7 @@ impl BytecodeDependencyOptimizer<'_> {
391377
let ContractDefinitionPart::FunctionDefinition(func) = node else {
392378
return None;
393379
};
394-
if *func.kind() != FunctionKind::Constructor {
380+
if *func.kind() != foundry_compilers_artifacts::FunctionKind::Constructor {
395381
return None;
396382
}
397383

0 commit comments

Comments
 (0)