Skip to content

Commit f0fa3c3

Browse files
committed
[jcw-gen] Generate Java Callable Wrappers in parallel.
Generate Java Callable Wrappers across multiple tasks. A note about the tests: when I first added jcw-gen I tried to use Tasks so I could get parallel JCW generation, but some of the output was unexpected, in that it would have the wrong package name. This is why the JavaCallableWrapperGeneratorTests.GenerateInParallel() test was added: to try to reproduce the error that I recalled seeing. Doing this found two unexpected bugs in `JniType.ToJniName()` (yay): 1. I was getting a `NullReferenceException` from `JniType.IsNonStaticInnerClass()`, because in `JniType.ToJniName<T>()` there is a call to `JniType.IsNonStaticInnerClass()` using the result of `as TypeDefinition`, but `IsNonStaticInnerClass()` never checked for `null`. Oops. 2. The reflection-based `JniType.ToJniName(Type)` overload didn't check for `Android.App.InstrumentationAttribute` providing an overriding `InstrumentationAttribute.Name` property.
1 parent 0276d9a commit f0fa3c3

File tree

4 files changed

+81
-12
lines changed

4 files changed

+81
-12
lines changed

src/Java.Interop.Tools.JavaCallableWrappers/Test/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616
<DebugType>full</DebugType>
1717
<Optimize>false</Optimize>
1818
<OutputPath>..\..\..\bin\TestDebug</OutputPath>
19-
<DefineConstants>DEBUG;JCW_ONLY_TYPE_NAMES</DefineConstants>
19+
<DefineConstants>DEBUG;HAVE_CECIL;JCW_ONLY_TYPE_NAMES</DefineConstants>
2020
<ErrorReport>prompt</ErrorReport>
2121
<WarningLevel>4</WarningLevel>
2222
<ConsolePause>false</ConsolePause>
2323
</PropertyGroup>
2424
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
2525
<Optimize>true</Optimize>
2626
<OutputPath>..\..\..\bin\TestRelease</OutputPath>
27-
<DefineConstants>JCW_ONLY_TYPE_NAMES</DefineConstants>
27+
<DefineConstants>HAVE_CECIL;JCW_ONLY_TYPE_NAMES</DefineConstants>
2828
<ErrorReport>prompt</ErrorReport>
2929
<WarningLevel>4</WarningLevel>
3030
<ConsolePause>false</ConsolePause>
@@ -56,10 +56,6 @@
5656
<None Include="packages.config" />
5757
</ItemGroup>
5858
<ItemGroup>
59-
<ProjectReference Include="..\jcw-gen.csproj">
60-
<Project>{52C7D9B6-E8C8-47D0-9471-652D278D7D77}</Project>
61-
<Name>jcw-gen</Name>
62-
</ProjectReference>
6359
<ProjectReference Include="..\Java.Interop.Tools.JavaCallableWrappers.csproj">
6460
<Project>{D18FCF91-8876-48A0-A693-2DC1E7D3D80A}</Project>
6561
<Name>Java.Interop.Tools.JavaCallableWrappers</Name>
@@ -76,6 +72,7 @@
7672
<ItemGroup>
7773
<Folder Include="Java.Interop.Tools.JavaCallableWrappers\" />
7874
</ItemGroup>
75+
<Import Project="..\..\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings.projitems" Label="Shared" Condition="Exists('..\..\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings.projitems')" />
7976
<Import Project="..\..\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems" Label="Shared" Condition="Exists('..\..\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems')" />
8077
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
8178
</Project>

src/Java.Interop.Tools.JavaCallableWrappers/Test/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGeneratorTests.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.IO;
3+
using System.Linq;
4+
using System.Threading.Tasks;
35

46
using Mono.Cecil;
57

@@ -8,6 +10,7 @@
810
using Java.Interop.Tools.Diagnostics;
911
using Java.Interop.Tools.JavaCallableWrappers;
1012
using Java.Interop.Tools.JavaCallableWrappersTests;
13+
using Java.Interop.Tools.TypeNameMappings;
1114

1215
using Xamarin.Android.ToolsTests;
1316

@@ -27,6 +30,69 @@ public void ConstructorExceptions ()
2730
Assert.AreEqual (4200, e.Code);
2831
}
2932

33+
[Test]
34+
public void GenerateInParallel ()
35+
{
36+
var assemblyDef = AssemblyDefinition.ReadAssembly (typeof (DefaultName).Assembly.Location);
37+
var types = new []{
38+
typeof (AbstractClassInvoker),
39+
typeof (AbstractClass),
40+
typeof (ActivityName),
41+
typeof (ApplicationName),
42+
typeof (DefaultName),
43+
typeof (DefaultName.A),
44+
typeof (DefaultName.A.B),
45+
typeof (DefaultName.C.D),
46+
// Skip because this will produce nested types
47+
// typeof (ExampleOuterClass),
48+
// typeof (ExampleOuterClass.ExampleInnerClass),
49+
typeof (InstrumentationName),
50+
// Skip because this will produce nested types
51+
// typeof (NonStaticOuterClass),
52+
// typeof (NonStaticOuterClass.NonStaticInnerClass),
53+
typeof (ProviderName),
54+
typeof (ReceiverName),
55+
typeof (RegisterName),
56+
typeof (RegisterName.DefaultNestedName),
57+
typeof (RegisterName.OverrideNestedName),
58+
typeof (ServiceName),
59+
};
60+
var typeDefs = types.Select (t => SupportDeclarations.GetTypeDefinition (t, assemblyDef))
61+
.ToList ();
62+
63+
var tasks = typeDefs.Select (type => Task.Run (() => {
64+
var g = new JavaCallableWrapperGenerator (type, log: Console.WriteLine);
65+
var o = new StringWriter ();
66+
g.Generate (o);
67+
var r = new StringReader (o.ToString ());
68+
var l = r.ReadLine ();
69+
if (!l.StartsWith ("package ", StringComparison.Ordinal))
70+
throw new InvalidOperationException ($"Invalid JCW for {type.FullName}!");
71+
var p = l.Substring ("package ".Length);
72+
p = p.Substring (0, p.Length - 1);
73+
l = r.ReadLine ();
74+
if (l.Length != 0)
75+
throw new InvalidOperationException ($"Invalid JCW for {type.FullName}! (Missing newline)");
76+
l = r.ReadLine ();
77+
if (l.Length != 0)
78+
throw new InvalidOperationException ($"Invalid JCW for {type.FullName}! (Missing 2nd newline)");
79+
l = r.ReadLine ();
80+
string c = null;
81+
if (l.StartsWith ("public class ", StringComparison.Ordinal))
82+
c = l.Substring ("public class ".Length);
83+
else if (l.StartsWith ("public abstract class ", StringComparison.Ordinal))
84+
c = l.Substring ("public abstract class ".Length);
85+
else
86+
throw new InvalidOperationException ($"Invalid JCW for {type.FullName}! (Missing class)");
87+
return p + "/" + c;
88+
})).ToArray ();
89+
Task.WaitAll (tasks);
90+
for (int i = 0; i < types.Length; ++i) {
91+
Assert.AreEqual (JniType.ToJniName (typeDefs [i]), tasks [i].Result);
92+
Assert.AreEqual (JniType.ToJniName (types [i]), tasks [i].Result);
93+
}
94+
}
95+
3096
[Test]
3197
public void GenerateApplication ()
3298
{

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ static string GetSpecialExportJniType (string typeName, ExportParameterKind expo
253253
}
254254

255255
#if !GEN_JAVA_STUBS && !GENERATOR && !JAVADOC_TO_MDOC
256-
// Keep in sync with ToJniName(TypeDefinition)
256+
// Keep in sync with ToJniNameFromAttributes(TypeDefinition)
257257
public static string ToJniNameFromAttributes (Type type)
258258
{
259259
var ras = (Android.Runtime.RegisterAttribute[]) type.GetCustomAttributes (typeof (Android.Runtime.RegisterAttribute), false);
@@ -280,6 +280,10 @@ public static string ToJniNameFromAttributes (Type type)
280280
if (cpas.Length > 0 && !string.IsNullOrEmpty (cpas [0].Name))
281281
return cpas [0].Name.Replace ('.', '/');
282282

283+
var ias = (Android.App.InstrumentationAttribute[])type.GetCustomAttributes (typeof (Android.App.InstrumentationAttribute), false);
284+
if (ias.Length > 0 && !string.IsNullOrEmpty (ias [0].Name))
285+
return ias [0].Name.Replace ('.', '/');
286+
283287
return null;
284288
}
285289

@@ -599,6 +603,8 @@ static string ToJniName<T> (T type, Func<T, T> decl, Func<T, string> name, Func<
599603
#if HAVE_CECIL
600604
internal static bool IsNonStaticInnerClass (TypeDefinition type)
601605
{
606+
if (type == null)
607+
return false;
602608
if (!type.IsNested)
603609
return false;
604610

tools/jcw-gen/App.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Linq;
33
using System.IO;
4+
using System.Threading.Tasks;
45

56
using Java.Interop.Tools.Cecil;
67
using Java.Interop.Tools.JavaCallableWrappers;
@@ -59,11 +60,10 @@ public static int Main (string [] args)
5960
resolver.SearchDirectories.Add (Path.GetDirectoryName (assembly));
6061
resolver.Load (assembly);
6162
}
62-
var types = JavaTypeScanner.GetJavaTypes (assemblies, resolver, log: Console.WriteLine)
63-
.Where (td => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration (td));
64-
foreach (var type in types) {
65-
GenerateJavaCallableWrapper (type, outputPath);
66-
}
63+
var tasks = JavaTypeScanner.GetJavaTypes (assemblies, resolver, log: Console.WriteLine)
64+
.Where (td => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration (td))
65+
.Select (td => Task.Run (() => GenerateJavaCallableWrapper (td, outputPath)));
66+
Task.WaitAll (tasks.ToArray ());
6767
return 0;
6868
}
6969
catch (Exception e) {

0 commit comments

Comments
 (0)