Skip to content

Commit 56b7eeb

Browse files
[Java.Interop.Tools.TypeNameMappings] fix trimmer warnings (#1194)
Context: https://github.com/xamarin/xamarin-android/blob/e987ac458536e59a8329a06d5c5d5f4d4ea2c6b6/src/Mono.Android/Mono.Android.csproj#L69-L71 In xamarin/xamarin-android's `Mono.Android.dll`, we [import][0] `Java.Interop.Tools.TypeNameMappings\JavaNativeTypeManager.cs`, and unfortunately that causes some trimmer warnings: external\Java.Interop\src\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings\JavaNativeTypeManager.cs(182,9): error IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.Interfaces' in call to 'System.Type.GetInterfaces()'. The parameter 'type' of method 'Java.Interop.Tools.TypeNameMappings.JavaNativeTypeManager.ToJniName(Type, ExportParameterKind)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. From the code: if (!type.GetInterfaces ().Any (t => t.FullName == "Android.Runtime.IJavaObject")) It appears we can instead look for `IJavaPeerable` and use trim-safe behavior instead: if (Type.GetType ("Java.Interop.IJavaPeerable, Java.Interop", throwOnError: true) .IsAssignableFrom (type)) I also cache the `Type.GetType()` call with `Lazy<T>`. However, in some cases we run this code under an MSBuild context. In this case, we don't have `Java.Interop.dll` to load, so we should instead use a variation on the previous code: type.GetInterfaces ().Any (t => t.FullName == "Java.Interop.IJavaPeerable"); To catch warnings in this project going forward: * Multi-target to `netstandard2.0` and `net8.0` using `$(DotNetTargetFramework)`. `netstandard2.0` is used for MSBuild-task assemblies inside VS. * Enable trimmer warnings for `net8.0`. Additionally, as I targeted `net8.0`, various null-reference-type warnings appeared, which I also fixed. [0]: https://github.com/xamarin/xamarin-android/blob/e199d62210bfb666595d95ca60579c5c766be1d6/src/Mono.Android/Mono.Android.csproj#L69-L71
1 parent c825dca commit 56b7eeb

File tree

6 files changed

+37
-11
lines changed

6 files changed

+37
-11
lines changed

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/CecilImporter.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -547,13 +547,13 @@ static IEnumerable<CallableWrapperTypeAnnotation> CreateAnnotations (ICustomAttr
547547
static string ManagedValueToJavaSource (object value)
548548
{
549549
if (value is string)
550-
return "\"" + value.ToString ().Replace ("\"", "\"\"") + '"';
550+
return "\"" + value.ToString ()?.Replace ("\"", "\"\"") + '"';
551551
else if (value.GetType ().FullName == "Java.Lang.Class")
552552
return value.ToString () + ".class";
553553
else if (value is bool v)
554554
return v ? "true" : "false";
555555
else
556-
return value.ToString ();
556+
return value.ToString () ?? "";
557557
}
558558

559559
static string GetJavaAccess (MethodAttributes access)

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperType.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ public void Generate (string outputPath, CallableWrapperWriterOptions options)
315315
StreamWriter OpenStream (string outputPath)
316316
{
317317
var destination = GetDestinationPath (outputPath);
318-
Directory.CreateDirectory (Path.GetDirectoryName (destination));
318+
Directory.CreateDirectory (Path.GetDirectoryName (destination)!);
319319

320320
return new StreamWriter (new FileStream (destination, FileMode.Create, FileAccess.Write));
321321
}

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.csproj

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>netstandard2.0</TargetFramework>
4+
<XAConfigPath>..\..\bin\Build$(Configuration)\XAConfig.props</XAConfigPath>
5+
</PropertyGroup>
6+
<Import Condition="Exists ('$(XAConfigPath)')" Project="$(XAConfigPath)" />
7+
8+
<PropertyGroup>
9+
<TargetFrameworks>netstandard2.0;$(DotNetTargetFramework)</TargetFrameworks>
510
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
611
<LangVersion>11.0</LangVersion>
712
<Nullable>enable</Nullable>
813
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
914
<SignAssembly>true</SignAssembly>
15+
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
1016
<AssemblyOriginatorKeyFile>..\..\product.snk</AssemblyOriginatorKeyFile>
1117
<DefineConstants>$(DefineConstants);JCW_ONLY_TYPE_NAMES;HAVE_CECIL</DefineConstants>
1218
</PropertyGroup>
@@ -17,13 +23,19 @@
1723
<OutputPath>$(ToolOutputFullPath)</OutputPath>
1824
</PropertyGroup>
1925

26+
<PropertyGroup Condition=" '$(TargetFramework)' != 'netstandard2.0' ">
27+
<IsTrimmable>true</IsTrimmable>
28+
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
29+
<EnableAotAnalyzer>true</EnableAotAnalyzer>
30+
</PropertyGroup>
31+
2032
<Import Project="..\..\build-tools\scripts\cecil.projitems" />
2133

2234
<ItemGroup>
2335
<Compile Include="..\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings\JavaNativeTypeManager.cs">
2436
<Link>JavaNativeTypeManager.cs</Link>
2537
</Compile>
26-
<Compile Include="..\utils\NullableAttributes.cs">
38+
<Compile Include="..\utils\NullableAttributes.cs" Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
2739
<Link>NullableAttributes.cs</Link>
2840
</Compile>
2941
</ItemGroup>

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/CecilExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static IEnumerable<ExportFieldAttribute> GetExportFieldAttributes (Mono.C
2222
public static IEnumerable<TAttribute> GetAttributes<TAttribute> (Mono.Cecil.ICustomAttributeProvider p, Func<CustomAttribute, TAttribute?> selector)
2323
where TAttribute : class
2424
{
25-
return GetAttributes (p, typeof (TAttribute).FullName, selector);
25+
return GetAttributes (p, typeof (TAttribute).FullName!, selector);
2626
}
2727

2828
public static IEnumerable<TAttribute> GetAttributes<TAttribute> (Mono.Cecil.ICustomAttributeProvider p, string attributeName, Func<CustomAttribute, TAttribute?> selector)

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ Dictionary<string, string> GetTypeMapping (Func<TypeDefinition, bool> skipType,
179179

180180
var k = key (type, Cache);
181181

182-
TypeDefinition e;
182+
TypeDefinition? e;
183183
if (!typeMap.TryGetValue (k, out e)) {
184184
typeMap.Add (k, type);
185185
} else if (type.IsAbstract || type.IsInterface || e.IsAbstract || e.IsInterface) {
@@ -190,7 +190,7 @@ Dictionary<string, string> GetTypeMapping (Func<TypeDefinition, bool> skipType,
190190
b = type;
191191
typeMap [k] = b;
192192
} else {
193-
List<string> a;
193+
List<string>? a;
194194
if (!aliases.TryGetValue (k, out a)) {
195195
aliases.Add (k, a = new List<string> ());
196196
a.Add (value (e, Cache));
@@ -266,7 +266,7 @@ public void WriteManagedToJava (Stream output)
266266

267267
class ArrayComparer<T> : IComparer<T[]> {
268268

269-
public int Compare (T[] x, T[] y)
269+
public int Compare (T []? x, T []? y)
270270
{
271271
if (x == null && y == null)
272272
return 0;

src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs

+16-2
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,29 @@ public static string ToJniName (Type type)
178178
if (type == typeof (string))
179179
return "java/lang/String";
180180

181-
182-
if (!type.GetInterfaces ().Any (t => t.FullName == "Android.Runtime.IJavaObject"))
181+
if (ShouldCheckSpecialExportJniType (type))
183182
return GetSpecialExportJniType (type.FullName!, exportKind);
184183

185184
return ToJniName (type, t => t.DeclaringType!, t => t.Name, GetPackageName, t => {
186185
return ToJniNameFromAttributes (t);
187186
}, _ => false);
188187
}
189188

189+
#if !NETSTANDARD2_0
190+
static readonly Lazy<Type> IJavaPeerableType = new Lazy<Type> (() =>
191+
Type.GetType ("Java.Interop.IJavaPeerable, Java.Interop", throwOnError: true)!
192+
);
193+
#endif
194+
195+
// NOTE: NETSTANDARD2_0 could be running in an MSBuild context where Java.Interop.dll is not available.
196+
// Trimming warnings are not enabled for netstandard2.0 in this project.
197+
static bool ShouldCheckSpecialExportJniType (Type type) =>
198+
#if NETSTANDARD2_0
199+
type.GetInterfaces ().Any (t => t.FullName == "Java.Interop.IJavaPeerable");
200+
#else
201+
IJavaPeerableType.Value.IsAssignableFrom (type);
202+
#endif
203+
190204
public static string ToJniName (string jniType, int rank)
191205
{
192206
if (rank == 0)

0 commit comments

Comments
 (0)