Skip to content

Commit

Permalink
[Xamarin.Android.Tools.Bytecode] Kotlin name shadowing support (#573)
Browse files Browse the repository at this point in the history
Fixes: #571

Don't mark `public` Kotlin methods as `private` if they "shadow" --
share the same name as -- a private property or field.

If a library uses Kotlin's `NAME_SHADOWING` we incorrectly match the
`private` property/field to the `public` method and mark the methods
as `private`.  Given Kotlin:

	@Suppress("NAME_SHADOWING")
	public class NameShadowing {
	    // Property and method
	    private val count: Int = 3
	    fun count(): Int = count
	    
	    // Field and method
	    private var hitCount = 0
	    fun hitCount(): Int = hitCount
	    
	    // Property and setter
	    private var type = 0
	    fun setType(type: Int) = { println (type); }
	}

Then the public methods `NameShadowing.count()`,
`NameShadowing.hitCount()`, and `NameShadowing.setType()` were not
present within the C# binding.

Support name shadowing by only considering `getFoo()` methods as
potential property getters, instead of allowing `foo`.  (Allowing
`foo` was likely incorrect anyways.)

Additionally, when considering if a method is a potential property
setter, also check that the method's return type is `void`.

[Xamarin.Android.Tools.Bytecode] Kotlin name shadowing support (#573)
  • Loading branch information
jpobst authored Feb 19, 2020
1 parent 5d8a60e commit 566a461
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,7 @@ static FieldInfo FindJavaFieldProperty (KotlinFile kotlinClass, KotlinProperty p

static MethodInfo FindJavaPropertyGetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass)
{
var possible_methods = klass.Methods.Where (method => (string.Compare (method.GetMethodNameWithoutSuffix (), $"get{property.Name}", true) == 0 ||
string.Compare (method.GetMethodNameWithoutSuffix (), property.Name, true) == 0) &&
var possible_methods = klass.Methods.Where (method => string.Compare (method.GetMethodNameWithoutSuffix (), $"get{property.Name}", true) == 0 &&
method.GetParameters ().Length == 0 &&
TypesMatch (method.ReturnType, property.ReturnType, kotlinClass));

Expand All @@ -245,6 +244,7 @@ static MethodInfo FindJavaPropertySetter (KotlinFile kotlinClass, KotlinProperty
var possible_methods = klass.Methods.Where (method => string.Compare (method.GetMethodNameWithoutSuffix (), $"set{property.Name}", true) == 0 &&
property.ReturnType != null &&
method.GetParameters ().Length == 1 &&
method.ReturnType.BinaryName == "V" &&
TypesMatch (method.GetParameters () [0].Type, property.ReturnType, kotlinClass));

return possible_methods.FirstOrDefault ();
Expand Down
12 changes: 12 additions & 0 deletions tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,5 +236,17 @@ public void UnsignedMethodsXml ()
Assert.AreEqual ("ubyte[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ubytearray-GBYM_sE").Attribute ("return").Value);
Assert.AreEqual ("ubyte[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ubytearray-GBYM_sE").Element ("parameter").Attribute ("type").Value);
}

[Test]
public void HandleKotlinNameShadowing ()
{
var klass = LoadClassFile ("NameShadowing.class");

KotlinFixups.Fixup (new [] { klass });

Assert.True (klass.Methods.Single (m => m.Name == "count").AccessFlags.HasFlag (MethodAccessFlags.Public));
Assert.True (klass.Methods.Single (m => m.Name == "hitCount").AccessFlags.HasFlag (MethodAccessFlags.Public));
Assert.True (klass.Methods.Single (m => m.Name == "setType").AccessFlags.HasFlag (MethodAccessFlags.Public));
}
}
}
Binary file not shown.
14 changes: 14 additions & 0 deletions tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/NameShadowing.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@Suppress("NAME_SHADOWING")
public class NameShadowing {
// Property and method
private val count: Int = 3
fun count(): Int = count

// Field and method
private var hitCount = 0
fun hitCount(): Int = hitCount

// Property and setter
private var type = 0
fun setType(type: Int) = { println (type); }
}

0 comments on commit 566a461

Please sign in to comment.