@@ -20,16 +20,16 @@ use std::{
20
20
21
21
/// Holds data about referenced source contracts and bytecode dependencies.
22
22
pub 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 > > ,
25
25
// Referenced contract ids.
26
26
pub referenced_contracts : HashSet < u32 > ,
27
27
}
28
28
29
29
impl 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 ( ) ;
33
33
for contract_id in Hir :: contract_ids ( hir) {
34
34
let contract = Hir :: contract ( hir, contract_id) ;
35
35
let source = Hir :: source ( hir, contract. source ) ;
@@ -43,18 +43,22 @@ impl PreprocessorDependencies {
43
43
continue ;
44
44
}
45
45
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
+ ) ;
48
52
// Analyze current contract.
49
53
deps_collector. walk_contract ( contract) ;
50
54
// Ignore empty test contracts declared in source files with other contracts.
51
55
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 ) ;
53
57
}
54
58
// Record collected referenced contract ids.
55
- references . extend ( deps_collector. referenced_contracts ) ;
59
+ referenced_contracts . extend ( deps_collector. referenced_contracts ) ;
56
60
}
57
- Self { bytecode_deps : inner , referenced_contracts : references }
61
+ Self { preprocessed_contracts , referenced_contracts }
58
62
}
59
63
}
60
64
@@ -86,22 +90,50 @@ struct BytecodeDependencyCollector<'hir> {
86
90
hir : & ' hir Hir < ' hir > ,
87
91
/// Source content of current contract.
88
92
src : & ' hir str ,
93
+ /// Project source dir, used to determine if referenced contract is a source contract.
94
+ src_dir : & ' hir PathBuf ,
89
95
/// Dependencies collected for current contract.
90
96
dependencies : Vec < BytecodeDependency > ,
91
- /// HIR ids of contracts referenced from current contract.
97
+ /// Unique HIR ids of contracts referenced from current contract.
92
98
referenced_contracts : HashSet < u32 > ,
93
99
}
94
100
95
101
impl < ' 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 {
97
108
Self {
98
109
source_map,
99
110
hir,
100
111
src,
112
+ src_dir,
101
113
dependencies : vec ! [ ] ,
102
114
referenced_contracts : HashSet :: default ( ) ,
103
115
}
104
116
}
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
+ }
105
137
}
106
138
107
139
impl < ' hir > Visit < ' hir > for BytecodeDependencyCollector < ' hir > {
@@ -121,15 +153,14 @@ impl<'hir> Visit<'hir> for BytecodeDependencyCollector<'hir> {
121
153
// TODO: check if there's a better way to determine where constructor call
122
154
// ends.
123
155
let args_len = self . src [ name_loc. end ..] . split_once ( ';' ) . unwrap ( ) . 0 . len ( ) ;
124
- self . dependencies . push ( BytecodeDependency {
156
+ self . collect_dependency ( BytecodeDependency {
125
157
kind : BytecodeDependencyKind :: New ( name. to_string ( ) , args_len) ,
126
158
loc : SourceMapLocation :: from_span (
127
159
self . source_map ,
128
160
Span :: new ( expr. span . lo ( ) , expr. span . hi ( ) ) ,
129
161
) ,
130
162
referenced_contract : contract_id. get ( ) ,
131
163
} ) ;
132
- self . referenced_contracts . insert ( contract_id. get ( ) ) ;
133
164
}
134
165
}
135
166
}
@@ -138,12 +169,11 @@ impl<'hir> Visit<'hir> for BytecodeDependencyCollector<'hir> {
138
169
if let ExprKind :: TypeCall ( ty) = & member_expr. kind {
139
170
if let TypeKind :: Custom ( contract_id) = & ty. kind {
140
171
if let Some ( contract_id) = contract_id. as_contract ( ) {
141
- self . dependencies . push ( BytecodeDependency {
172
+ self . collect_dependency ( BytecodeDependency {
142
173
kind : BytecodeDependencyKind :: CreationCode ,
143
174
loc : SourceMapLocation :: from_span ( self . source_map , expr. span ) ,
144
175
referenced_contract : contract_id. get ( ) ,
145
176
} ) ;
146
- self . referenced_contracts . insert ( contract_id. get ( ) ) ;
147
177
}
148
178
}
149
179
}
@@ -163,7 +193,7 @@ pub fn remove_bytecode_dependencies(
163
193
data : & PreprocessorData ,
164
194
) -> Updates {
165
195
let mut updates = Updates :: default ( ) ;
166
- for ( contract_id, deps) in & deps. bytecode_deps {
196
+ for ( contract_id, deps) in & deps. preprocessed_contracts {
167
197
let contract = Hir :: contract ( hir, ContractId :: new ( * contract_id) ) ;
168
198
let source = Hir :: source ( hir, contract. source ) ;
169
199
let FileName :: Real ( path) = & source. file . name else {
0 commit comments