Skip to content

Commit

Permalink
[generator] Strip arity from Cecil imported types. (#450)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jpobst authored and jonpryor committed Jul 19, 2019
1 parent 2ec06c9 commit 262743b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 4 deletions.
20 changes: 20 additions & 0 deletions tools/generator/Extensions/ManagedExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ public static IEnumerable<Parameter> GetParameters (this MethodDefinition m, Cus
yield return CecilApiImporter.CreateParameter (p, type, rawtype);
}
}

public static string StripArity (this string type)
{
if (string.IsNullOrWhiteSpace (type))
return type;

int tick_index;

// Need to loop for things like List`1<List`1<string>>
while ((tick_index = type.IndexOf ('`')) >= 0) {
var less_than_index = type.IndexOf ('<', tick_index);

if (less_than_index == -1)
return type;

type = type.Substring (0, tick_index) + type.Substring (less_than_index);
}

return type;
}
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public static Field CreateField (FieldDefinition f)
IsStatic = f.IsStatic,
JavaName = reg_attr != null ? ((string) reg_attr.ConstructorArguments [0].Value).Replace ('/', '.') : f.Name,
Name = f.Name,
TypeName = f.FieldType.FullNameCorrected (),
TypeName = f.FieldType.FullNameCorrected ().StripArity (),
Value = f.Constant == null ? null : f.FieldType.FullName == "System.String" ? '"' + f.Constant.ToString () + '"' : f.Constant.ToString (),
Visibility = f.IsPublic ? "public" : f.IsFamilyOrAssembly ? "protected internal" : f.IsFamily ? "protected" : f.IsAssembly ? "internal" : "private"
};
Expand Down Expand Up @@ -181,8 +181,8 @@ public static Method CreateMethod (GenBase declaringType, MethodDefinition m)
IsStatic = m.IsStatic,
IsVirtual = m.IsVirtual,
JavaName = reg_attr != null ? ((string) reg_attr.ConstructorArguments [0].Value) : m.Name,
ManagedReturn = m.ReturnType.FullNameCorrected (),
Return = m.ReturnType.FullNameCorrected (),
ManagedReturn = m.ReturnType.FullNameCorrected ().StripArity (),
Return = m.ReturnType.FullNameCorrected ().StripArity (),
Visibility = m.Visibility ()
};

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

public static Parameter CreateParameter (string managedType, string javaType)
Expand Down
31 changes: 31 additions & 0 deletions tools/generator/Tests/Unit-Tests/ManagedExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MonoDroid.Generation;
using NUnit.Framework;

namespace generatortests
{
[TestFixture]
public class ManagedExtensionsTests
{
[Test]
public void StripArity ()
{
Assert.AreEqual ("List<string>", "List`1<string>".StripArity ());
Assert.AreEqual ("List<List<string>>", "List`10<List`1<string>>".StripArity ());
Assert.AreEqual ("List<string>", "List<string>".StripArity ());
Assert.AreEqual ("List`1", "List`1".StripArity ());
Assert.AreEqual ("L<blah>ist<string>", "L<blah>ist`1<string>".StripArity ());
Assert.AreEqual ("List<string>", "List`1`<string>".StripArity ());
Assert.AreEqual ("List<<string>", "List`1<<string>".StripArity ());
Assert.AreEqual ("List<", "List`<".StripArity ());
Assert.AreEqual ("<", "`1<".StripArity ());
Assert.AreEqual ("`", "`".StripArity ());
Assert.AreEqual (string.Empty, string.Empty.StripArity ());
Assert.IsNull ((null as string).StripArity ());
}
}
}
44 changes: 44 additions & 0 deletions tools/generator/Tests/Unit-Tests/ManagedTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Mono.Cecil;
using MonoDroid.Generation;
using NUnit.Framework;
using System.Collections.Generic;
using System.IO;
using System.Linq;

Expand Down Expand Up @@ -42,6 +43,27 @@ public void UnknownTypes (object unknown) { }
public interface IService { }
}

namespace GenericTestClasses
{
public class MyCollection<T> : List<T>
{
[Register ("mycollection", "()V", "")]
public MyCollection (List<T> p0, List<string> p1)
{
}

public List<T> field;

public Dictionary<string, T> field2;

[Register ("dostuff", "()V", "")]
public Dictionary<T, List<string>> DoStuff (IEnumerable<KeyValuePair<T, List<List<T>>>> p)
{
return new Dictionary<T, List<string>> ();
}
}
}

namespace generatortests
{
[TestFixture]
Expand Down Expand Up @@ -206,5 +228,27 @@ public void Interface ()
Assert.AreEqual ("com.mypackage.service", @interface.JavaName);
Assert.AreEqual ("Lcom/mypackage/service;", @interface.JniName);
}

[Test]
public void StripArity ()
{
var @class = CecilApiImporter.CreateClass (module.GetType ("GenericTestClasses.MyCollection`1"), options);

// Class (Leave Arity on types)
Assert.AreEqual ("GenericTestClasses.MyCollection`1", @class.FullName);

// Constructor
Assert.AreEqual ("System.Collections.Generic.List<T>", @class.Ctors [0].Parameters [0].RawNativeType);
Assert.AreEqual ("System.Collections.Generic.List<System.String>", @class.Ctors [0].Parameters [1].RawNativeType);

// Field
Assert.AreEqual ("System.Collections.Generic.List<T>", @class.Fields [0].TypeName);
Assert.AreEqual ("System.Collections.Generic.Dictionary<System.String,T>", @class.Fields [1].TypeName);

// Method
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);
Assert.AreEqual ("System.Collections.Generic.Dictionary<T,System.Collections.Generic.List<System.String>>", @class.Methods [0].ReturnType);
Assert.AreEqual ("System.Collections.Generic.Dictionary<T,System.Collections.Generic.List<System.String>>", @class.Methods [0].ManagedReturn);
}
}
}
1 change: 1 addition & 0 deletions tools/generator/Tests/generator-Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<Compile Include="Unit-Tests\AdjusterTests.cs" />
<Compile Include="Unit-Tests\DefaultInterfaceMethodsTests.cs" />
<Compile Include="Unit-Tests\EnumGeneratorTests.cs" />
<Compile Include="Unit-Tests\ManagedExtensionsTests.cs" />
<Compile Include="Unit-Tests\ManagedTests.cs" />
<Compile Include="Unit-Tests\SupportTypes.cs" />
<Compile Include="Unit-Tests\TestExtensions.cs" />
Expand Down

0 comments on commit 262743b

Please sign in to comment.