@@ -25,18 +25,6 @@ use wit_component::{StringEncoding, WitPrinter};
25
25
mod csproj;
26
26
pub use csproj:: CSProject ;
27
27
28
- //TODO remove unused
29
- const CSHARP_IMPORTS : & str = "\
30
- using System;
31
- using System.Runtime.CompilerServices;
32
- using System.Collections;
33
- using System.Runtime.InteropServices;
34
- using System.Text;
35
- using System.Collections.Generic;
36
- using System.Diagnostics;
37
- using System.Diagnostics.CodeAnalysis;
38
- " ;
39
-
40
28
#[ derive( Default , Debug , Clone ) ]
41
29
#[ cfg_attr( feature = "clap" , derive( clap:: Args ) ) ]
42
30
pub struct Opts {
@@ -106,6 +94,8 @@ struct InterfaceFragment {
106
94
csharp_src : String ,
107
95
csharp_interop_src : String ,
108
96
stub : String ,
97
+ usings : HashSet < String > ,
98
+ interop_usings : HashSet < String > ,
109
99
}
110
100
111
101
pub struct InterfaceTypeAndFragments {
@@ -133,6 +123,8 @@ pub enum FunctionLevel {
133
123
pub struct CSharp {
134
124
opts : Opts ,
135
125
name : String ,
126
+ usings : HashSet < String > ,
127
+ interop_usings : HashSet < String > ,
136
128
return_area_size : usize ,
137
129
return_area_align : usize ,
138
130
tuple_counts : HashSet < usize > ,
@@ -180,6 +172,8 @@ impl CSharp {
180
172
resolve,
181
173
name,
182
174
direction,
175
+ usings : HashSet :: < String > :: new ( ) ,
176
+ interop_usings : HashSet :: < String > :: new ( ) ,
183
177
}
184
178
}
185
179
@@ -196,6 +190,20 @@ impl CSharp {
196
190
( String :: new ( ) , String :: new ( ) )
197
191
}
198
192
}
193
+
194
+ fn require_using ( & mut self , using_ns : & str ) {
195
+ if !self . usings . contains ( using_ns) {
196
+ let using_ns_string = using_ns. to_string ( ) ;
197
+ self . usings . insert ( using_ns_string) ;
198
+ }
199
+ }
200
+
201
+ fn require_interop_using ( & mut self , using_ns : & str ) {
202
+ if !self . interop_usings . contains ( using_ns) {
203
+ let using_ns_string = using_ns. to_string ( ) ;
204
+ self . interop_usings . insert ( using_ns_string) ;
205
+ }
206
+ }
199
207
}
200
208
201
209
impl WorldGenerator for CSharp {
@@ -405,10 +413,11 @@ impl WorldGenerator for CSharp {
405
413
406
414
let access = self . access_modifier ( ) ;
407
415
416
+ let using_pos = src. len ( ) ;
417
+
408
418
uwrite ! (
409
419
src,
410
- "{CSHARP_IMPORTS}
411
-
420
+ "
412
421
namespace {world_namespace} {{
413
422
414
423
{access} interface I{name}World {{
@@ -424,6 +433,16 @@ impl WorldGenerator for CSharp {
424
433
. join ( "\n " ) ,
425
434
) ;
426
435
436
+ let usings: Vec < _ > = self
437
+ . world_fragments
438
+ . iter ( )
439
+ . flat_map ( |f| & f. usings )
440
+ . cloned ( )
441
+ . collect ( ) ;
442
+ usings. iter ( ) . for_each ( |u| {
443
+ self . require_using ( u) ;
444
+ } ) ;
445
+
427
446
let mut producers = wasm_metadata:: Producers :: empty ( ) ;
428
447
producers. add (
429
448
"processed-by" ,
@@ -434,6 +453,7 @@ impl WorldGenerator for CSharp {
434
453
src. push_str ( "}\n " ) ;
435
454
436
455
if self . needs_result {
456
+ self . require_using ( "System.Runtime.InteropServices" ) ;
437
457
uwrite ! (
438
458
src,
439
459
r#"
@@ -495,6 +515,7 @@ impl WorldGenerator for CSharp {
495
515
}
496
516
497
517
if self . needs_option {
518
+ self . require_using ( "System.Diagnostics.CodeAnalysis" ) ;
498
519
uwrite ! (
499
520
src,
500
521
r#"
@@ -525,6 +546,8 @@ impl WorldGenerator for CSharp {
525
546
}
526
547
527
548
if self . needs_interop_string {
549
+ self . require_using ( "System.Text" ) ;
550
+ self . require_using ( "System.Runtime.InteropServices" ) ;
528
551
uwrite ! (
529
552
src,
530
553
r#"
@@ -568,6 +591,8 @@ impl WorldGenerator for CSharp {
568
591
569
592
let ( array_size, element_type) =
570
593
dotnet_aligned_array ( self . return_area_size , self . return_area_align ) ;
594
+
595
+ self . require_using ( "System.Runtime.CompilerServices" ) ;
571
596
uwrite ! (
572
597
ret_area_str,
573
598
"
@@ -607,6 +632,17 @@ impl WorldGenerator for CSharp {
607
632
src. push_str ( "\n " ) ;
608
633
609
634
src. push_str ( "namespace exports {\n " ) ;
635
+
636
+ src. push_str (
637
+ & self
638
+ . world_fragments
639
+ . iter ( )
640
+ . flat_map ( |f| & f. interop_usings )
641
+ . map ( |s| "using " . to_owned ( ) + s + ";" )
642
+ . collect :: < Vec < String > > ( )
643
+ . join ( "\n " ) ,
644
+ ) ;
645
+
610
646
src. push_str ( & format ! ( "{access} static class {name}World\n " ) ) ;
611
647
src. push_str ( "{" ) ;
612
648
@@ -623,6 +659,16 @@ impl WorldGenerator for CSharp {
623
659
624
660
src. push_str ( "}\n " ) ;
625
661
662
+ src. insert_str (
663
+ using_pos,
664
+ & self
665
+ . usings
666
+ . iter ( )
667
+ . map ( |s| "using " . to_owned ( ) + s + ";" )
668
+ . collect :: < Vec < String > > ( )
669
+ . join ( "\n " ) ,
670
+ ) ;
671
+
626
672
files. push ( & format ! ( "{name}.cs" ) , indent ( & src) . as_bytes ( ) ) ;
627
673
628
674
let generate_stub = |name : String , files : & mut Files , stubs : Stubs | {
@@ -668,8 +714,6 @@ impl WorldGenerator for CSharp {
668
714
669
715
let body = format ! (
670
716
"{header}
671
- {CSHARP_IMPORTS}
672
-
673
717
namespace {fully_qualified_namespace};
674
718
675
719
{access} partial class {stub_class_name} : {interface_or_class_name} {{
@@ -789,14 +833,20 @@ impl WorldGenerator for CSharp {
789
833
if body. len ( ) > 0 {
790
834
let body = format ! (
791
835
"{header}
792
- {CSHARP_IMPORTS }
836
+ {0 }
793
837
794
838
namespace {namespace};
795
839
796
840
{access} interface {interface_name} {{
797
841
{body}
798
842
}}
799
- "
843
+ " ,
844
+ fragments
845
+ . iter( )
846
+ . flat_map( |f| & f. usings)
847
+ . map( |s| "using " . to_owned( ) + s + ";" )
848
+ . collect:: <Vec <String >>( )
849
+ . join( "\n " ) ,
800
850
) ;
801
851
802
852
files. push ( & format ! ( "{full_name}.cs" ) , indent ( & body) . as_bytes ( ) ) ;
@@ -812,15 +862,21 @@ impl WorldGenerator for CSharp {
812
862
let class_name = interface_name. strip_prefix ( "I" ) . unwrap ( ) ;
813
863
let body = format ! (
814
864
"{header}
815
- {CSHARP_IMPORTS }
865
+ {0 }
816
866
817
867
namespace {namespace}
818
868
{{
819
869
{access} static class {class_name}Interop {{
820
870
{body}
821
871
}}
822
872
}}
823
- "
873
+ " ,
874
+ fragments
875
+ . iter( )
876
+ . flat_map( |f| & f. interop_usings)
877
+ . map( |s| "using " . to_owned( ) + s + ";\n " )
878
+ . collect:: <Vec <String >>( )
879
+ . join( "" ) ,
824
880
) ;
825
881
826
882
files. push (
@@ -845,6 +901,8 @@ struct InterfaceGenerator<'a> {
845
901
resolve : & ' a Resolve ,
846
902
name : & ' a str ,
847
903
direction : Direction ,
904
+ usings : HashSet < String > ,
905
+ interop_usings : HashSet < String > ,
848
906
}
849
907
850
908
impl InterfaceGenerator < ' _ > {
@@ -956,6 +1014,8 @@ impl InterfaceGenerator<'_> {
956
1014
csharp_src : self . src ,
957
1015
csharp_interop_src : self . csharp_interop_src ,
958
1016
stub : self . stub ,
1017
+ usings : self . usings ,
1018
+ interop_usings : self . interop_usings ,
959
1019
} ) ;
960
1020
}
961
1021
@@ -964,6 +1024,8 @@ impl InterfaceGenerator<'_> {
964
1024
csharp_src : self . src ,
965
1025
csharp_interop_src : self . csharp_interop_src ,
966
1026
stub : self . stub ,
1027
+ usings : self . usings ,
1028
+ interop_usings : self . interop_usings ,
967
1029
} ) ;
968
1030
}
969
1031
@@ -1083,8 +1145,10 @@ impl InterfaceGenerator<'_> {
1083
1145
let import_name = & func. name ;
1084
1146
1085
1147
let target = if let FunctionKind :: Freestanding = & func. kind {
1148
+ self . require_interop_using ( "System.Runtime.InteropServices" ) ;
1086
1149
& mut self . csharp_interop_src
1087
1150
} else {
1151
+ self . require_using ( "System.Runtime.InteropServices" ) ;
1088
1152
& mut self . src
1089
1153
} ;
1090
1154
@@ -1229,6 +1293,7 @@ impl InterfaceGenerator<'_> {
1229
1293
let export_name = func. legacy_core_export_name ( core_module_name. as_deref ( ) ) ;
1230
1294
let access = self . gen . access_modifier ( ) ;
1231
1295
1296
+ self . require_interop_using ( "System.Runtime.InteropServices" ) ;
1232
1297
uwrite ! (
1233
1298
self . csharp_interop_src,
1234
1299
r#"
@@ -1429,6 +1494,20 @@ impl InterfaceGenerator<'_> {
1429
1494
}
1430
1495
}
1431
1496
1497
+ fn require_using ( & mut self , using_ns : & str ) {
1498
+ if !self . usings . contains ( using_ns) {
1499
+ let using_ns_string = using_ns. to_string ( ) ;
1500
+ self . usings . insert ( using_ns_string) ;
1501
+ }
1502
+ }
1503
+
1504
+ fn require_interop_using ( & mut self , using_ns : & str ) {
1505
+ if !self . interop_usings . contains ( using_ns) {
1506
+ let using_ns_string = using_ns. to_string ( ) ;
1507
+ self . interop_usings . insert ( using_ns_string) ;
1508
+ }
1509
+ }
1510
+
1432
1511
fn start_resource ( & mut self , id : TypeId , key : Option < & WorldKey > ) {
1433
1512
let access = self . gen . access_modifier ( ) ;
1434
1513
let qualified = self . type_name_with_qualifier ( & Type :: Id ( id) , true ) ;
@@ -1444,6 +1523,7 @@ impl InterfaceGenerator<'_> {
1444
1523
. map ( |key| self . resolve . name_world_key ( key) )
1445
1524
. unwrap_or_else ( || "$root" . into ( ) ) ;
1446
1525
1526
+ self . require_using ( "System.Runtime.InteropServices" ) ;
1447
1527
// As of this writing, we cannot safely drop a handle to an imported resource from a .NET finalizer
1448
1528
// because it may still have one or more open child resources. Once WIT has explicit syntax for
1449
1529
// indicating parent/child relationships, we should be able to use that information to keep track
@@ -1482,6 +1562,7 @@ impl InterfaceGenerator<'_> {
1482
1562
. map ( |s| format ! ( "{}#" , self . resolve. name_world_key( s) ) )
1483
1563
. unwrap_or_else ( String :: new) ;
1484
1564
1565
+ self . require_interop_using ( "System.Runtime.InteropServices" ) ;
1485
1566
uwrite ! (
1486
1567
self . csharp_interop_src,
1487
1568
r#"
@@ -1500,6 +1581,7 @@ impl InterfaceGenerator<'_> {
1500
1581
. map ( |key| format ! ( "[export]{}" , self . resolve. name_world_key( key) ) )
1501
1582
. unwrap_or_else ( || "[export]$root" . into ( ) ) ;
1502
1583
1584
+ self . require_using ( "System.Runtime.InteropServices" ) ;
1503
1585
// The ergonomics of exported resources are not ideal, currently. Implementing such a resource
1504
1586
// requires both extending a class and implementing an interface. The reason for the class is to
1505
1587
// allow implementers to inherit code which tracks and disposes of the resource handle; the reason
@@ -2584,10 +2666,18 @@ impl Bindgen for FunctionBindgen<'_, '_> {
2584
2666
self . gen . gen . needs_interop_string = true ;
2585
2667
}
2586
2668
2587
- Instruction :: StringLift { .. } => results. push ( format ! (
2588
- "Encoding.UTF8.GetString((byte*){}, {})" ,
2589
- operands[ 0 ] , operands[ 1 ]
2590
- ) ) ,
2669
+ Instruction :: StringLift { .. } => {
2670
+ if FunctionKind :: Freestanding == * self . kind || self . gen . direction == Direction :: Export {
2671
+ self . gen . require_interop_using ( "System.Text" ) ;
2672
+ } else {
2673
+ self . gen . require_using ( "System.Text" ) ;
2674
+ }
2675
+
2676
+ results. push ( format ! (
2677
+ "Encoding.UTF8.GetString((byte*){}, {})" ,
2678
+ operands[ 0 ] , operands[ 1 ]
2679
+ ) ) ;
2680
+ }
2591
2681
2592
2682
Instruction :: ListLower { element, realloc } => {
2593
2683
let Block {
0 commit comments