Skip to content

Commit 1739caf

Browse files
authored
[C#] minor improvement to reduce unused using statements (#1070)
* minor improvement to reduce unused using statements * tidy usings, update to net10 * cargo fmt
1 parent 6d0120f commit 1739caf

File tree

2 files changed

+116
-26
lines changed

2 files changed

+116
-26
lines changed

crates/csharp/src/csproj.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ impl CSProjectLLVMBuilder {
9292
csproj.push_str(
9393
r#"
9494
<ItemGroup>
95-
<PackageReference Include="Microsoft.DotNet.ILCompiler.LLVM" Version="9.0.0-rc.1.24412.1" />
96-
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="9.0.0-rc.1.24412.1" />
95+
<PackageReference Include="Microsoft.DotNet.ILCompiler.LLVM" Version="10.0.0-*" />
96+
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="10.0.0-*" />
9797
</ItemGroup>
9898
"#,
9999
);

crates/csharp/src/lib.rs

Lines changed: 114 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,6 @@ use wit_component::{StringEncoding, WitPrinter};
2525
mod csproj;
2626
pub use csproj::CSProject;
2727

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-
4028
#[derive(Default, Debug, Clone)]
4129
#[cfg_attr(feature = "clap", derive(clap::Args))]
4230
pub struct Opts {
@@ -106,6 +94,8 @@ struct InterfaceFragment {
10694
csharp_src: String,
10795
csharp_interop_src: String,
10896
stub: String,
97+
usings: HashSet<String>,
98+
interop_usings: HashSet<String>,
10999
}
110100

111101
pub struct InterfaceTypeAndFragments {
@@ -133,6 +123,8 @@ pub enum FunctionLevel {
133123
pub struct CSharp {
134124
opts: Opts,
135125
name: String,
126+
usings: HashSet<String>,
127+
interop_usings: HashSet<String>,
136128
return_area_size: usize,
137129
return_area_align: usize,
138130
tuple_counts: HashSet<usize>,
@@ -180,6 +172,8 @@ impl CSharp {
180172
resolve,
181173
name,
182174
direction,
175+
usings: HashSet::<String>::new(),
176+
interop_usings: HashSet::<String>::new(),
183177
}
184178
}
185179

@@ -196,6 +190,20 @@ impl CSharp {
196190
(String::new(), String::new())
197191
}
198192
}
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+
}
199207
}
200208

201209
impl WorldGenerator for CSharp {
@@ -405,10 +413,11 @@ impl WorldGenerator for CSharp {
405413

406414
let access = self.access_modifier();
407415

416+
let using_pos = src.len();
417+
408418
uwrite!(
409419
src,
410-
"{CSHARP_IMPORTS}
411-
420+
"
412421
namespace {world_namespace} {{
413422
414423
{access} interface I{name}World {{
@@ -424,6 +433,16 @@ impl WorldGenerator for CSharp {
424433
.join("\n"),
425434
);
426435

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+
427446
let mut producers = wasm_metadata::Producers::empty();
428447
producers.add(
429448
"processed-by",
@@ -434,6 +453,7 @@ impl WorldGenerator for CSharp {
434453
src.push_str("}\n");
435454

436455
if self.needs_result {
456+
self.require_using("System.Runtime.InteropServices");
437457
uwrite!(
438458
src,
439459
r#"
@@ -495,6 +515,7 @@ impl WorldGenerator for CSharp {
495515
}
496516

497517
if self.needs_option {
518+
self.require_using("System.Diagnostics.CodeAnalysis");
498519
uwrite!(
499520
src,
500521
r#"
@@ -525,6 +546,8 @@ impl WorldGenerator for CSharp {
525546
}
526547

527548
if self.needs_interop_string {
549+
self.require_using("System.Text");
550+
self.require_using("System.Runtime.InteropServices");
528551
uwrite!(
529552
src,
530553
r#"
@@ -568,6 +591,8 @@ impl WorldGenerator for CSharp {
568591

569592
let (array_size, element_type) =
570593
dotnet_aligned_array(self.return_area_size, self.return_area_align);
594+
595+
self.require_using("System.Runtime.CompilerServices");
571596
uwrite!(
572597
ret_area_str,
573598
"
@@ -607,6 +632,17 @@ impl WorldGenerator for CSharp {
607632
src.push_str("\n");
608633

609634
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+
610646
src.push_str(&format!("{access} static class {name}World\n"));
611647
src.push_str("{");
612648

@@ -623,6 +659,16 @@ impl WorldGenerator for CSharp {
623659

624660
src.push_str("}\n");
625661

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+
626672
files.push(&format!("{name}.cs"), indent(&src).as_bytes());
627673

628674
let generate_stub = |name: String, files: &mut Files, stubs: Stubs| {
@@ -668,8 +714,6 @@ impl WorldGenerator for CSharp {
668714

669715
let body = format!(
670716
"{header}
671-
{CSHARP_IMPORTS}
672-
673717
namespace {fully_qualified_namespace};
674718
675719
{access} partial class {stub_class_name} : {interface_or_class_name} {{
@@ -789,14 +833,20 @@ impl WorldGenerator for CSharp {
789833
if body.len() > 0 {
790834
let body = format!(
791835
"{header}
792-
{CSHARP_IMPORTS}
836+
{0}
793837
794838
namespace {namespace};
795839
796840
{access} interface {interface_name} {{
797841
{body}
798842
}}
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"),
800850
);
801851

802852
files.push(&format!("{full_name}.cs"), indent(&body).as_bytes());
@@ -812,15 +862,21 @@ impl WorldGenerator for CSharp {
812862
let class_name = interface_name.strip_prefix("I").unwrap();
813863
let body = format!(
814864
"{header}
815-
{CSHARP_IMPORTS}
865+
{0}
816866
817867
namespace {namespace}
818868
{{
819869
{access} static class {class_name}Interop {{
820870
{body}
821871
}}
822872
}}
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(""),
824880
);
825881

826882
files.push(
@@ -845,6 +901,8 @@ struct InterfaceGenerator<'a> {
845901
resolve: &'a Resolve,
846902
name: &'a str,
847903
direction: Direction,
904+
usings: HashSet<String>,
905+
interop_usings: HashSet<String>,
848906
}
849907

850908
impl InterfaceGenerator<'_> {
@@ -956,6 +1014,8 @@ impl InterfaceGenerator<'_> {
9561014
csharp_src: self.src,
9571015
csharp_interop_src: self.csharp_interop_src,
9581016
stub: self.stub,
1017+
usings: self.usings,
1018+
interop_usings: self.interop_usings,
9591019
});
9601020
}
9611021

@@ -964,6 +1024,8 @@ impl InterfaceGenerator<'_> {
9641024
csharp_src: self.src,
9651025
csharp_interop_src: self.csharp_interop_src,
9661026
stub: self.stub,
1027+
usings: self.usings,
1028+
interop_usings: self.interop_usings,
9671029
});
9681030
}
9691031

@@ -1083,8 +1145,10 @@ impl InterfaceGenerator<'_> {
10831145
let import_name = &func.name;
10841146

10851147
let target = if let FunctionKind::Freestanding = &func.kind {
1148+
self.require_interop_using("System.Runtime.InteropServices");
10861149
&mut self.csharp_interop_src
10871150
} else {
1151+
self.require_using("System.Runtime.InteropServices");
10881152
&mut self.src
10891153
};
10901154

@@ -1229,6 +1293,7 @@ impl InterfaceGenerator<'_> {
12291293
let export_name = func.legacy_core_export_name(core_module_name.as_deref());
12301294
let access = self.gen.access_modifier();
12311295

1296+
self.require_interop_using("System.Runtime.InteropServices");
12321297
uwrite!(
12331298
self.csharp_interop_src,
12341299
r#"
@@ -1429,6 +1494,20 @@ impl InterfaceGenerator<'_> {
14291494
}
14301495
}
14311496

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+
14321511
fn start_resource(&mut self, id: TypeId, key: Option<&WorldKey>) {
14331512
let access = self.gen.access_modifier();
14341513
let qualified = self.type_name_with_qualifier(&Type::Id(id), true);
@@ -1444,6 +1523,7 @@ impl InterfaceGenerator<'_> {
14441523
.map(|key| self.resolve.name_world_key(key))
14451524
.unwrap_or_else(|| "$root".into());
14461525

1526+
self.require_using("System.Runtime.InteropServices");
14471527
// As of this writing, we cannot safely drop a handle to an imported resource from a .NET finalizer
14481528
// because it may still have one or more open child resources. Once WIT has explicit syntax for
14491529
// indicating parent/child relationships, we should be able to use that information to keep track
@@ -1482,6 +1562,7 @@ impl InterfaceGenerator<'_> {
14821562
.map(|s| format!("{}#", self.resolve.name_world_key(s)))
14831563
.unwrap_or_else(String::new);
14841564

1565+
self.require_interop_using("System.Runtime.InteropServices");
14851566
uwrite!(
14861567
self.csharp_interop_src,
14871568
r#"
@@ -1500,6 +1581,7 @@ impl InterfaceGenerator<'_> {
15001581
.map(|key| format!("[export]{}", self.resolve.name_world_key(key)))
15011582
.unwrap_or_else(|| "[export]$root".into());
15021583

1584+
self.require_using("System.Runtime.InteropServices");
15031585
// The ergonomics of exported resources are not ideal, currently. Implementing such a resource
15041586
// requires both extending a class and implementing an interface. The reason for the class is to
15051587
// allow implementers to inherit code which tracks and disposes of the resource handle; the reason
@@ -2584,10 +2666,18 @@ impl Bindgen for FunctionBindgen<'_, '_> {
25842666
self.gen.gen.needs_interop_string = true;
25852667
}
25862668

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+
}
25912681

25922682
Instruction::ListLower { element, realloc } => {
25932683
let Block {

0 commit comments

Comments
 (0)