Skip to content

Commit

Permalink
[Java.Interop.Tools.TypeNameMappings] fix trimmer warnings (#1194)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jonathanpeppers authored Feb 21, 2024
1 parent c825dca commit 56b7eeb
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -547,13 +547,13 @@ static IEnumerable<CallableWrapperTypeAnnotation> CreateAnnotations (ICustomAttr
static string ManagedValueToJavaSource (object value)
{
if (value is string)
return "\"" + value.ToString ().Replace ("\"", "\"\"") + '"';
return "\"" + value.ToString ()?.Replace ("\"", "\"\"") + '"';
else if (value.GetType ().FullName == "Java.Lang.Class")
return value.ToString () + ".class";
else if (value is bool v)
return v ? "true" : "false";
else
return value.ToString ();
return value.ToString () ?? "";
}

static string GetJavaAccess (MethodAttributes access)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ public void Generate (string outputPath, CallableWrapperWriterOptions options)
StreamWriter OpenStream (string outputPath)
{
var destination = GetDestinationPath (outputPath);
Directory.CreateDirectory (Path.GetDirectoryName (destination));
Directory.CreateDirectory (Path.GetDirectoryName (destination)!);

return new StreamWriter (new FileStream (destination, FileMode.Create, FileAccess.Write));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<XAConfigPath>..\..\bin\Build$(Configuration)\XAConfig.props</XAConfigPath>
</PropertyGroup>
<Import Condition="Exists ('$(XAConfigPath)')" Project="$(XAConfigPath)" />

<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DotNetTargetFramework)</TargetFrameworks>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<LangVersion>11.0</LangVersion>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<SignAssembly>true</SignAssembly>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<AssemblyOriginatorKeyFile>..\..\product.snk</AssemblyOriginatorKeyFile>
<DefineConstants>$(DefineConstants);JCW_ONLY_TYPE_NAMES;HAVE_CECIL</DefineConstants>
</PropertyGroup>
Expand All @@ -17,13 +23,19 @@
<OutputPath>$(ToolOutputFullPath)</OutputPath>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' != 'netstandard2.0' ">
<IsTrimmable>true</IsTrimmable>
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
<EnableAotAnalyzer>true</EnableAotAnalyzer>
</PropertyGroup>

<Import Project="..\..\build-tools\scripts\cecil.projitems" />

<ItemGroup>
<Compile Include="..\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings\JavaNativeTypeManager.cs">
<Link>JavaNativeTypeManager.cs</Link>
</Compile>
<Compile Include="..\utils\NullableAttributes.cs">
<Compile Include="..\utils\NullableAttributes.cs" Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<Link>NullableAttributes.cs</Link>
</Compile>
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static IEnumerable<ExportFieldAttribute> GetExportFieldAttributes (Mono.C
public static IEnumerable<TAttribute> GetAttributes<TAttribute> (Mono.Cecil.ICustomAttributeProvider p, Func<CustomAttribute, TAttribute?> selector)
where TAttribute : class
{
return GetAttributes (p, typeof (TAttribute).FullName, selector);
return GetAttributes (p, typeof (TAttribute).FullName!, selector);
}

public static IEnumerable<TAttribute> GetAttributes<TAttribute> (Mono.Cecil.ICustomAttributeProvider p, string attributeName, Func<CustomAttribute, TAttribute?> selector)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ Dictionary<string, string> GetTypeMapping (Func<TypeDefinition, bool> skipType,

var k = key (type, Cache);

TypeDefinition e;
TypeDefinition? e;
if (!typeMap.TryGetValue (k, out e)) {
typeMap.Add (k, type);
} else if (type.IsAbstract || type.IsInterface || e.IsAbstract || e.IsInterface) {
Expand All @@ -190,7 +190,7 @@ Dictionary<string, string> GetTypeMapping (Func<TypeDefinition, bool> skipType,
b = type;
typeMap [k] = b;
} else {
List<string> a;
List<string>? a;
if (!aliases.TryGetValue (k, out a)) {
aliases.Add (k, a = new List<string> ());
a.Add (value (e, Cache));
Expand Down Expand Up @@ -266,7 +266,7 @@ public void WriteManagedToJava (Stream output)

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

public int Compare (T[] x, T[] y)
public int Compare (T []? x, T []? y)
{
if (x == null && y == null)
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,29 @@ public static string ToJniName (Type type)
if (type == typeof (string))
return "java/lang/String";


if (!type.GetInterfaces ().Any (t => t.FullName == "Android.Runtime.IJavaObject"))
if (ShouldCheckSpecialExportJniType (type))
return GetSpecialExportJniType (type.FullName!, exportKind);

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

#if !NETSTANDARD2_0
static readonly Lazy<Type> IJavaPeerableType = new Lazy<Type> (() =>
Type.GetType ("Java.Interop.IJavaPeerable, Java.Interop", throwOnError: true)!
);
#endif

// NOTE: NETSTANDARD2_0 could be running in an MSBuild context where Java.Interop.dll is not available.
// Trimming warnings are not enabled for netstandard2.0 in this project.
static bool ShouldCheckSpecialExportJniType (Type type) =>
#if NETSTANDARD2_0
type.GetInterfaces ().Any (t => t.FullName == "Java.Interop.IJavaPeerable");
#else
IJavaPeerableType.Value.IsAssignableFrom (type);
#endif

public static string ToJniName (string jniType, int rank)
{
if (rank == 0)
Expand Down

0 comments on commit 56b7eeb

Please sign in to comment.