Skip to content

Commit 262743b

Browse files
jpobstjonpryor
authored andcommitted
[generator] Strip arity from Cecil imported types. (#450)
Context: #424 One of the issues trying to bind the BouncyCastle-provided [`bcprov-ext-jdk15on-161.jar.`][0] in #424 is that we write generic types with invalid signatures: public List`1<string> MyProperty { get; set; } as this is how a Cecil type reference `FullName` is returned. Since this notation is not useful to us, strip the "arity" information when reading the assembly. This results in the proper type syntax: public List<string> MyProperty { get; set; } [0]: https://www.bouncycastle.org/download/bcprov-ext-jdk15on-161.jar
1 parent 2ec06c9 commit 262743b

File tree

5 files changed

+100
-4
lines changed

5 files changed

+100
-4
lines changed

tools/generator/Extensions/ManagedExtensions.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,26 @@ public static IEnumerable<Parameter> GetParameters (this MethodDefinition m, Cus
4545
yield return CecilApiImporter.CreateParameter (p, type, rawtype);
4646
}
4747
}
48+
49+
public static string StripArity (this string type)
50+
{
51+
if (string.IsNullOrWhiteSpace (type))
52+
return type;
53+
54+
int tick_index;
55+
56+
// Need to loop for things like List`1<List`1<string>>
57+
while ((tick_index = type.IndexOf ('`')) >= 0) {
58+
var less_than_index = type.IndexOf ('<', tick_index);
59+
60+
if (less_than_index == -1)
61+
return type;
62+
63+
type = type.Substring (0, tick_index) + type.Substring (less_than_index);
64+
}
65+
66+
return type;
67+
}
4868
}
4969
#endif
5070
}

tools/generator/Java.Interop.Tools.Generator.Importers/CecilApiImporter.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public static Field CreateField (FieldDefinition f)
9393
IsStatic = f.IsStatic,
9494
JavaName = reg_attr != null ? ((string) reg_attr.ConstructorArguments [0].Value).Replace ('/', '.') : f.Name,
9595
Name = f.Name,
96-
TypeName = f.FieldType.FullNameCorrected (),
96+
TypeName = f.FieldType.FullNameCorrected ().StripArity (),
9797
Value = f.Constant == null ? null : f.FieldType.FullName == "System.String" ? '"' + f.Constant.ToString () + '"' : f.Constant.ToString (),
9898
Visibility = f.IsPublic ? "public" : f.IsFamilyOrAssembly ? "protected internal" : f.IsFamily ? "protected" : f.IsAssembly ? "internal" : "private"
9999
};
@@ -181,8 +181,8 @@ public static Method CreateMethod (GenBase declaringType, MethodDefinition m)
181181
IsStatic = m.IsStatic,
182182
IsVirtual = m.IsVirtual,
183183
JavaName = reg_attr != null ? ((string) reg_attr.ConstructorArguments [0].Value) : m.Name,
184-
ManagedReturn = m.ReturnType.FullNameCorrected (),
185-
Return = m.ReturnType.FullNameCorrected (),
184+
ManagedReturn = m.ReturnType.FullNameCorrected ().StripArity (),
185+
Return = m.ReturnType.FullNameCorrected ().StripArity (),
186186
Visibility = m.Visibility ()
187187
};
188188

@@ -211,7 +211,7 @@ public static Parameter CreateParameter (ParameterDefinition p, string jnitype,
211211
// FIXME: safe to use CLR type name? assuming yes as we often use it in metadatamap.
212212
// FIXME: IsSender?
213213
var isEnumType = GetGeneratedEnumAttribute (p.CustomAttributes) != null;;
214-
return new Parameter (SymbolTable.MangleName (p.Name), jnitype ?? p.ParameterType.FullNameCorrected (), null, isEnumType, rawtype);
214+
return new Parameter (SymbolTable.MangleName (p.Name), jnitype ?? p.ParameterType.FullNameCorrected ().StripArity (), null, isEnumType, rawtype);
215215
}
216216

217217
public static Parameter CreateParameter (string managedType, string javaType)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using MonoDroid.Generation;
7+
using NUnit.Framework;
8+
9+
namespace generatortests
10+
{
11+
[TestFixture]
12+
public class ManagedExtensionsTests
13+
{
14+
[Test]
15+
public void StripArity ()
16+
{
17+
Assert.AreEqual ("List<string>", "List`1<string>".StripArity ());
18+
Assert.AreEqual ("List<List<string>>", "List`10<List`1<string>>".StripArity ());
19+
Assert.AreEqual ("List<string>", "List<string>".StripArity ());
20+
Assert.AreEqual ("List`1", "List`1".StripArity ());
21+
Assert.AreEqual ("L<blah>ist<string>", "L<blah>ist`1<string>".StripArity ());
22+
Assert.AreEqual ("List<string>", "List`1`<string>".StripArity ());
23+
Assert.AreEqual ("List<<string>", "List`1<<string>".StripArity ());
24+
Assert.AreEqual ("List<", "List`<".StripArity ());
25+
Assert.AreEqual ("<", "`1<".StripArity ());
26+
Assert.AreEqual ("`", "`".StripArity ());
27+
Assert.AreEqual (string.Empty, string.Empty.StripArity ());
28+
Assert.IsNull ((null as string).StripArity ());
29+
}
30+
}
31+
}

tools/generator/Tests/Unit-Tests/ManagedTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Mono.Cecil;
33
using MonoDroid.Generation;
44
using NUnit.Framework;
5+
using System.Collections.Generic;
56
using System.IO;
67
using System.Linq;
78

@@ -42,6 +43,27 @@ public void UnknownTypes (object unknown) { }
4243
public interface IService { }
4344
}
4445

46+
namespace GenericTestClasses
47+
{
48+
public class MyCollection<T> : List<T>
49+
{
50+
[Register ("mycollection", "()V", "")]
51+
public MyCollection (List<T> p0, List<string> p1)
52+
{
53+
}
54+
55+
public List<T> field;
56+
57+
public Dictionary<string, T> field2;
58+
59+
[Register ("dostuff", "()V", "")]
60+
public Dictionary<T, List<string>> DoStuff (IEnumerable<KeyValuePair<T, List<List<T>>>> p)
61+
{
62+
return new Dictionary<T, List<string>> ();
63+
}
64+
}
65+
}
66+
4567
namespace generatortests
4668
{
4769
[TestFixture]
@@ -206,5 +228,27 @@ public void Interface ()
206228
Assert.AreEqual ("com.mypackage.service", @interface.JavaName);
207229
Assert.AreEqual ("Lcom/mypackage/service;", @interface.JniName);
208230
}
231+
232+
[Test]
233+
public void StripArity ()
234+
{
235+
var @class = CecilApiImporter.CreateClass (module.GetType ("GenericTestClasses.MyCollection`1"), options);
236+
237+
// Class (Leave Arity on types)
238+
Assert.AreEqual ("GenericTestClasses.MyCollection`1", @class.FullName);
239+
240+
// Constructor
241+
Assert.AreEqual ("System.Collections.Generic.List<T>", @class.Ctors [0].Parameters [0].RawNativeType);
242+
Assert.AreEqual ("System.Collections.Generic.List<System.String>", @class.Ctors [0].Parameters [1].RawNativeType);
243+
244+
// Field
245+
Assert.AreEqual ("System.Collections.Generic.List<T>", @class.Fields [0].TypeName);
246+
Assert.AreEqual ("System.Collections.Generic.Dictionary<System.String,T>", @class.Fields [1].TypeName);
247+
248+
// Method
249+
Assert.AreEqual ("System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<T,System.Collections.Generic.List<System.Collections.Generic.List<T>>>>", @class.Methods [0].Parameters [0].RawNativeType);
250+
Assert.AreEqual ("System.Collections.Generic.Dictionary<T,System.Collections.Generic.List<System.String>>", @class.Methods [0].ReturnType);
251+
Assert.AreEqual ("System.Collections.Generic.Dictionary<T,System.Collections.Generic.List<System.String>>", @class.Methods [0].ManagedReturn);
252+
}
209253
}
210254
}

tools/generator/Tests/generator-Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
<Compile Include="Unit-Tests\AdjusterTests.cs" />
7575
<Compile Include="Unit-Tests\DefaultInterfaceMethodsTests.cs" />
7676
<Compile Include="Unit-Tests\EnumGeneratorTests.cs" />
77+
<Compile Include="Unit-Tests\ManagedExtensionsTests.cs" />
7778
<Compile Include="Unit-Tests\ManagedTests.cs" />
7879
<Compile Include="Unit-Tests\SupportTypes.cs" />
7980
<Compile Include="Unit-Tests\TestExtensions.cs" />

0 commit comments

Comments
 (0)