@@ -16,74 +16,100 @@ use foundry_compilers_artifacts::{
1616use foundry_compilers_core:: utils;
1717use itertools:: Itertools ;
1818use md5:: Digest ;
19+ use solar_parse:: {
20+ ast:: { Span , Visibility } ,
21+ interface:: diagnostics:: EmittedDiagnostics ,
22+ } ;
1923use std:: {
2024 collections:: { BTreeMap , BTreeSet } ,
2125 path:: { Path , PathBuf } ,
2226} ;
23- use solar_parse:: interface:: diagnostics:: Diagnostic ;
2427
2528/// Removes parts of the contract which do not alter its interface:
2629/// - Internal functions
2730/// - External functions bodies
2831///
2932/// Preserves all libraries and interfaces.
30- pub ( crate ) fn interface_representation ( content : & str ) -> Result < String , Vec < Diagnostic > > {
31- // let (source_unit, _) = solang_parser::parse(content, 0)?;
32- // let mut locs_to_remove = Vec::new();
33- //
34- // for part in source_unit.0 {
35- // if let pt::SourceUnitPart::ContractDefinition(contract) = part {
36- // if matches!(contract.ty, pt::ContractTy::Interface(_) | pt::ContractTy::Library(_)) {
37- // continue;
38- // }
39- // for part in contract.parts {
40- // if let pt::ContractPart::FunctionDefinition(func) = part {
41- // let is_exposed = func.ty == pt::FunctionTy::Function
42- // && func.attributes.iter().any(|attr| {
43- // matches!(
44- // attr,
45- // pt::FunctionAttribute::Visibility(
46- // pt::Visibility::External(_) | pt::Visibility::Public(_)
47- // )
48- // )
49- // })
50- // || matches!(
51- // func.ty,
52- // pt::FunctionTy::Constructor
53- // | pt::FunctionTy::Fallback
54- // | pt::FunctionTy::Receive
55- // );
56- //
57- // if !is_exposed {
58- // locs_to_remove.push(func.loc);
59- // }
60- //
61- // if let Some(ref body) = func.body {
62- // locs_to_remove.push(body.loc());
63- // }
64- // }
65- // }
66- // }
67- // }
68- //
69- // let mut content = content.to_string();
70- // let mut offset = 0;
71- //
72- // for loc in locs_to_remove {
73- // let start = loc.start() - offset;
74- // let end = loc.end() - offset;
75- //
76- // content.replace_range(start..end, "");
77- // offset += end - start;
78- // }
33+ pub ( crate ) fn interface_representation (
34+ content : & str ,
35+ file : & PathBuf ,
36+ ) -> Result < String , EmittedDiagnostics > {
37+ let mut spans_to_remove: Vec < Span > = Vec :: new ( ) ;
38+ let sess =
39+ solar_parse:: interface:: Session :: builder ( ) . with_buffer_emitter ( Default :: default ( ) ) . build ( ) ;
40+ sess. enter ( || {
41+ let arena = solar_parse:: ast:: Arena :: new ( ) ;
42+ let filename = solar_parse:: interface:: source_map:: FileName :: Real ( file. to_path_buf ( ) ) ;
43+ let Ok ( mut parser) =
44+ solar_parse:: Parser :: from_source_code ( & sess, & arena, filename, content. to_string ( ) )
45+ else {
46+ return ;
47+ } ;
48+ let Ok ( ast) = parser. parse_file ( ) . map_err ( |e| e. emit ( ) ) else { return } ;
49+ for item in ast. items {
50+ if let solar_parse:: ast:: ItemKind :: Contract ( contract) = & item. kind {
51+ if contract. kind . is_interface ( ) | contract. kind . is_library ( ) {
52+ continue ;
53+ }
54+ for contract_item in contract. body . iter ( ) {
55+ if let solar_parse:: ast:: ItemKind :: Function ( function) = & contract_item. kind {
56+ let is_exposed = match function. kind {
57+ // 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+ } )
63+ }
64+ solar_parse:: ast:: FunctionKind :: Constructor
65+ | solar_parse:: ast:: FunctionKind :: Fallback
66+ | solar_parse:: ast:: FunctionKind :: Receive => true ,
67+ // Other (modifiers)
68+ _ => false ,
69+ } ;
70+
71+ // If function is not exposed we remove the entire span (signature and
72+ // body). Otherwise we keep function signature and
73+ // remove only the body.
74+ if !is_exposed {
75+ spans_to_remove. push ( contract_item. span ) ;
76+ } else {
77+ spans_to_remove. push ( function. body_span ) ;
78+ }
79+ }
80+ }
81+ }
82+ }
83+ } ) ;
84+
85+ // Return original content if errors.
86+ if let Err ( err) = sess. emitted_errors ( ) . unwrap ( ) {
87+ let e = err. to_string ( ) ;
88+ trace ! ( "failed parsing {file:?}: {e}" ) ;
89+ return Err ( err) ;
90+ }
91+
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+ }
79103
80104 let content = content. replace ( "\n " , "" ) ;
81105 Ok ( utils:: RE_TWO_OR_MORE_SPACES . replace_all ( & content, "" ) . to_string ( ) )
82106}
83107
84108/// Computes hash of [`interface_representation`] of the source.
85- pub ( crate ) fn interface_representation_hash ( source : & Source ) -> String {
86- let Ok ( repr) = interface_representation ( & source. content ) else { return source. content_hash ( ) } ;
109+ pub ( crate ) fn interface_representation_hash ( source : & Source , file : & PathBuf ) -> String {
110+ let Ok ( repr) = interface_representation ( & source. content , file) else {
111+ return source. content_hash ( ) ;
112+ } ;
87113 let mut hasher = md5:: Md5 :: new ( ) ;
88114 hasher. update ( & repr) ;
89115 let result = hasher. finalize ( ) ;
@@ -278,7 +304,7 @@ impl ContractData<'_> {
278304
279305 let abi_encode_args =
280306 params. parameters . iter ( ) . map ( |param| format ! ( "args.{}" , param. name) ) . join ( ", " ) ;
281-
307+
282308 let vm_interface_name = format ! ( "VmContractHelper{}" , ast_id) ;
283309 let vm = format ! ( "{vm_interface_name}(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)" ) ;
284310
@@ -477,7 +503,10 @@ impl BytecodeDependencyOptimizer<'_> {
477503 updates. insert ( (
478504 new_loc. start ,
479505 new_loc. end ,
480- format ! ( "deployCode{id}(DeployHelper{id}.ConstructorArgs" , id = dep. referenced_contract) ,
506+ format ! (
507+ "deployCode{id}(DeployHelper{id}.ConstructorArgs" ,
508+ id = dep. referenced_contract
509+ ) ,
481510 ) ) ;
482511 updates. insert ( ( dep. loc . end , dep. loc . end , ")" . to_string ( ) ) ) ;
483512 }
@@ -605,7 +634,7 @@ contract A {
605634 }
606635}"# ;
607636
608- let result = interface_representation ( content) . unwrap ( ) ;
637+ let result = interface_representation ( content, & PathBuf :: new ( ) ) . unwrap ( ) ;
609638 assert_eq ! (
610639 result,
611640 r#"library Lib {function libFn() internal {// logic to keep}}contract A {function a() externalfunction b() publicfunction e() external }"#
0 commit comments