@@ -157,8 +157,11 @@ impl ProcessedData {
157157 ///
158158 /// This is useful if you intend to save the type libraries to disk in a finalized form.
159159 pub fn prune ( self ) -> Self {
160- let is_empty =
161- |tl : & TypeLibrary | tl. named_types ( ) . is_empty ( ) && tl. named_objects ( ) . is_empty ( ) ;
160+ let is_empty = |tl : & TypeLibrary | {
161+ tl. named_types ( ) . is_empty ( )
162+ && tl. named_type_declarations ( ) . is_empty ( )
163+ && tl. named_objects ( ) . is_empty ( )
164+ } ;
162165 let pruned_type_libraries = self
163166 . type_libraries
164167 . into_iter ( )
@@ -205,6 +208,11 @@ impl ProcessedData {
205208 for named_type in & tl. named_types ( ) {
206209 merged_type_library. add_named_type ( named_type. name . clone ( ) , & named_type. ty ) ;
207210 }
211+ // A definition from any library wins over a declaration, whatever the merge order.
212+ for declaration in & tl. named_type_declarations ( ) {
213+ merged_type_library
214+ . add_named_type_declaration ( declaration. name , declaration. type_class ) ;
215+ }
208216 for named_object in & tl. named_objects ( ) {
209217 merged_type_library
210218 . add_named_object ( named_object. name . clone ( ) , & named_object. ty ) ;
@@ -298,7 +306,10 @@ impl ProcessedData {
298306 // we can relocate them as well, assuming no other type library also uses it.
299307 let is_associated = default_type_library
300308 . get_named_type ( ntr_name. clone ( ) )
301- . is_some ( ) ;
309+ . is_some ( )
310+ || default_type_library
311+ . get_named_type_declaration ( ntr_name. clone ( ) )
312+ . is_some ( ) ;
302313 if is_associated {
303314 recorded_references
304315 . entry ( ntr_name)
@@ -327,10 +338,14 @@ impl ProcessedData {
327338 if type_libraries. len ( ) == 1 {
328339 // Only one type library uses this type, so we can safely relocate it.
329340 let type_library = type_libraries. iter ( ) . next ( ) . unwrap ( ) ;
330- let named_ty = default_type_library
331- . get_named_type ( qualified_name. clone ( ) )
332- . unwrap ( ) ;
333- type_library. add_named_type ( qualified_name, & named_ty) ;
341+ if let Some ( named_ty) = default_type_library. get_named_type ( qualified_name. clone ( ) )
342+ {
343+ type_library. add_named_type ( qualified_name, & named_ty) ;
344+ } else if let Some ( type_class) =
345+ default_type_library. get_named_type_declaration ( qualified_name. clone ( ) )
346+ {
347+ type_library. add_named_type_declaration ( qualified_name, type_class) ;
348+ }
334349 }
335350 }
336351 }
@@ -738,6 +753,14 @@ impl TypeLibProcessor {
738753 for t in tl. named_types ( ) . iter ( ) {
739754 type_name_to_library. insert ( t. name . clone ( ) , lib_name. clone ( ) ) ;
740755 }
756+ // Map declared names to the declaring library so the library being built records a type
757+ // source instead of copying the view's definition. A library that defines the name takes
758+ // precedence.
759+ for declaration in & tl. named_type_declarations ( ) {
760+ type_name_to_library
761+ . entry ( declaration. name )
762+ . or_insert_with ( || lib_name. clone ( ) ) ;
763+ }
741764 }
742765
743766 let add_referenced_types = |type_library : & TypeLibrary , ty : & Type | {
@@ -1309,4 +1332,42 @@ mod tests {
13091332 assert_eq ! ( merged_tl. platform_names( ) . len( ) , 2 ) ;
13101333 assert_eq ! ( merged_tl. named_types( ) . len( ) , 2 ) ;
13111334 }
1335+
1336+ #[ test]
1337+ fn test_data_merging_keeps_declarations ( ) {
1338+ use binaryninja:: types:: { NamedTypeDeclaration , NamedTypeReferenceClass } ;
1339+
1340+ let _session =
1341+ binaryninja:: headless:: Session :: new ( ) . expect ( "Failed to create headless session" ) ;
1342+ let x86_platform = Platform :: by_name ( "x86" ) . expect ( "Failed to get x86 platform" ) ;
1343+ let tl1 = TypeLibrary :: new ( x86_platform. arch ( ) , "foo" ) ;
1344+ tl1. set_dependency_name ( "foo" ) ;
1345+ tl1. add_platform ( & x86_platform) ;
1346+ tl1. add_named_type_declaration (
1347+ "declared" . into ( ) ,
1348+ NamedTypeReferenceClass :: StructNamedTypeClass ,
1349+ ) ;
1350+ tl1. add_named_type_declaration (
1351+ "defined" . into ( ) ,
1352+ NamedTypeReferenceClass :: StructNamedTypeClass ,
1353+ ) ;
1354+ let tl1_data = ProcessedData :: new ( vec ! [ tl1] ) ;
1355+
1356+ let tl2 = TypeLibrary :: new ( x86_platform. arch ( ) , "bar" ) ;
1357+ tl2. set_dependency_name ( "foo" ) ;
1358+ tl2. add_platform ( & x86_platform) ;
1359+ tl2. add_named_type ( "defined" . into ( ) , & Type :: named_int ( 4 , false , "defined" ) ) ;
1360+ let tl2_data = ProcessedData :: new ( vec ! [ tl2] ) ;
1361+
1362+ let merged_data = ProcessedData :: merge ( & [ tl1_data, tl2_data] ) ;
1363+ let merged_tl = & merged_data. type_libraries . iter ( ) . next ( ) . unwrap ( ) ;
1364+ assert_eq ! (
1365+ merged_tl. named_type_declarations( ) . to_vec( ) ,
1366+ vec![ NamedTypeDeclaration {
1367+ name: "declared" . into( ) ,
1368+ type_class: NamedTypeReferenceClass :: StructNamedTypeClass ,
1369+ } ]
1370+ ) ;
1371+ assert ! ( merged_tl. get_named_type( "defined" . into( ) ) . is_some( ) ) ;
1372+ }
13121373}
0 commit comments