@@ -20,16 +20,16 @@ use std::{
2020
2121/// Holds data about referenced source contracts and bytecode dependencies.
2222pub struct PreprocessorDependencies {
23- // Mapping test contract id -> test contract bytecode dependencies.
24- pub bytecode_deps : BTreeMap < u32 , Vec < BytecodeDependency > > ,
23+ // Mapping contract id to preprocess -> contract bytecode dependencies.
24+ pub preprocessed_contracts : BTreeMap < u32 , Vec < BytecodeDependency > > ,
2525 // Referenced contract ids.
2626 pub referenced_contracts : HashSet < u32 > ,
2727}
2828
2929impl PreprocessorDependencies {
30- pub fn new ( sess : & Session , hir : & Hir < ' _ > , paths : & [ PathBuf ] ) -> Self {
31- let mut inner = BTreeMap :: new ( ) ;
32- let mut references = HashSet :: default ( ) ;
30+ pub fn new ( sess : & Session , hir : & Hir < ' _ > , paths : & [ PathBuf ] , src_dir : & PathBuf ) -> Self {
31+ let mut preprocessed_contracts = BTreeMap :: new ( ) ;
32+ let mut referenced_contracts = HashSet :: new ( ) ;
3333 for contract_id in Hir :: contract_ids ( hir) {
3434 let contract = Hir :: contract ( hir, contract_id) ;
3535 let source = Hir :: source ( hir, contract. source ) ;
@@ -43,18 +43,22 @@ impl PreprocessorDependencies {
4343 continue ;
4444 }
4545
46- let mut deps_collector =
47- BytecodeDependencyCollector :: new ( sess. source_map ( ) , hir, source. file . src . as_str ( ) ) ;
46+ let mut deps_collector = BytecodeDependencyCollector :: new (
47+ sess. source_map ( ) ,
48+ hir,
49+ source. file . src . as_str ( ) ,
50+ src_dir,
51+ ) ;
4852 // Analyze current contract.
4953 deps_collector. walk_contract ( contract) ;
5054 // Ignore empty test contracts declared in source files with other contracts.
5155 if !deps_collector. dependencies . is_empty ( ) {
52- inner . insert ( contract_id. get ( ) , deps_collector. dependencies ) ;
56+ preprocessed_contracts . insert ( contract_id. get ( ) , deps_collector. dependencies ) ;
5357 }
5458 // Record collected referenced contract ids.
55- references . extend ( deps_collector. referenced_contracts ) ;
59+ referenced_contracts . extend ( deps_collector. referenced_contracts ) ;
5660 }
57- Self { bytecode_deps : inner , referenced_contracts : references }
61+ Self { preprocessed_contracts , referenced_contracts }
5862 }
5963}
6064
@@ -86,22 +90,50 @@ struct BytecodeDependencyCollector<'hir> {
8690 hir : & ' hir Hir < ' hir > ,
8791 /// Source content of current contract.
8892 src : & ' hir str ,
93+ /// Project source dir, used to determine if referenced contract is a source contract.
94+ src_dir : & ' hir PathBuf ,
8995 /// Dependencies collected for current contract.
9096 dependencies : Vec < BytecodeDependency > ,
91- /// HIR ids of contracts referenced from current contract.
97+ /// Unique HIR ids of contracts referenced from current contract.
9298 referenced_contracts : HashSet < u32 > ,
9399}
94100
95101impl < ' hir > BytecodeDependencyCollector < ' hir > {
96- fn new ( source_map : & ' hir SourceMap , hir : & ' hir Hir < ' hir > , src : & ' hir str ) -> Self {
102+ fn new (
103+ source_map : & ' hir SourceMap ,
104+ hir : & ' hir Hir < ' hir > ,
105+ src : & ' hir str ,
106+ src_dir : & ' hir PathBuf ,
107+ ) -> Self {
97108 Self {
98109 source_map,
99110 hir,
100111 src,
112+ src_dir,
101113 dependencies : vec ! [ ] ,
102114 referenced_contracts : HashSet :: default ( ) ,
103115 }
104116 }
117+
118+ /// Collects reference identified as bytecode dependency of analyzed contract.
119+ /// Discards any reference that is not in project src directory (e.g. external
120+ /// libraries or mock contracts that extend source contracts).
121+ fn collect_dependency ( & mut self , dependency : BytecodeDependency ) {
122+ let contract = Hir :: contract ( self . hir , ContractId :: new ( dependency. referenced_contract ) ) ;
123+ let source = Hir :: source ( self . hir , contract. source ) ;
124+ let FileName :: Real ( path) = & source. file . name else {
125+ return ;
126+ } ;
127+
128+ if !path. starts_with ( self . src_dir ) {
129+ let path = path. display ( ) ;
130+ println ! ( "ignore dependency {path}" ) ;
131+ return ;
132+ }
133+
134+ self . referenced_contracts . insert ( dependency. referenced_contract ) ;
135+ self . dependencies . push ( dependency) ;
136+ }
105137}
106138
107139impl < ' hir > Visit < ' hir > for BytecodeDependencyCollector < ' hir > {
@@ -121,15 +153,14 @@ impl<'hir> Visit<'hir> for BytecodeDependencyCollector<'hir> {
121153 // TODO: check if there's a better way to determine where constructor call
122154 // ends.
123155 let args_len = self . src [ name_loc. end ..] . split_once ( ';' ) . unwrap ( ) . 0 . len ( ) ;
124- self . dependencies . push ( BytecodeDependency {
156+ self . collect_dependency ( BytecodeDependency {
125157 kind : BytecodeDependencyKind :: New ( name. to_string ( ) , args_len) ,
126158 loc : SourceMapLocation :: from_span (
127159 self . source_map ,
128160 Span :: new ( expr. span . lo ( ) , expr. span . hi ( ) ) ,
129161 ) ,
130162 referenced_contract : contract_id. get ( ) ,
131163 } ) ;
132- self . referenced_contracts . insert ( contract_id. get ( ) ) ;
133164 }
134165 }
135166 }
@@ -138,12 +169,11 @@ impl<'hir> Visit<'hir> for BytecodeDependencyCollector<'hir> {
138169 if let ExprKind :: TypeCall ( ty) = & member_expr. kind {
139170 if let TypeKind :: Custom ( contract_id) = & ty. kind {
140171 if let Some ( contract_id) = contract_id. as_contract ( ) {
141- self . dependencies . push ( BytecodeDependency {
172+ self . collect_dependency ( BytecodeDependency {
142173 kind : BytecodeDependencyKind :: CreationCode ,
143174 loc : SourceMapLocation :: from_span ( self . source_map , expr. span ) ,
144175 referenced_contract : contract_id. get ( ) ,
145176 } ) ;
146- self . referenced_contracts . insert ( contract_id. get ( ) ) ;
147177 }
148178 }
149179 }
@@ -163,7 +193,7 @@ pub fn remove_bytecode_dependencies(
163193 data : & PreprocessorData ,
164194) -> Updates {
165195 let mut updates = Updates :: default ( ) ;
166- for ( contract_id, deps) in & deps. bytecode_deps {
196+ for ( contract_id, deps) in & deps. preprocessed_contracts {
167197 let contract = Hir :: contract ( hir, ContractId :: new ( * contract_id) ) ;
168198 let source = Hir :: source ( hir, contract. source ) ;
169199 let FileName :: Real ( path) = & source. file . name else {
0 commit comments