Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] Add MSBuild support for DIM.
Browse files Browse the repository at this point in the history
  • Loading branch information
jpobst committed Sep 4, 2019
1 parent 97f345a commit 2736e5b
Show file tree
Hide file tree
Showing 12 changed files with 261 additions and 2 deletions.
29 changes: 29 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public class BindingsGenerator : AndroidToolTask
[Required]
public string MonoAndroidFrameworkDirectories { get; set; }

public string LangVersion { get; set; }

public bool EnableInterfaceMembersPreview { get; set; }

public ITaskItem[] TransformFiles { get; set; }
public ITaskItem[] ReferencedManagedLibraries { get; set; }
public ITaskItem[] AnnotationsZipFiles { get; set; }
Expand Down Expand Up @@ -131,6 +135,9 @@ protected override string GenerateCommandLineCommands ()
if (UseShortFileNames)
cmd.AppendSwitch ("--use-short-file-names");

if (EnableInterfaceMembersPreview && SupportsCSharp8)
cmd.AppendSwitch ("--lang-features=interface-constants,default-interface-methods");

return cmd.ToString ();
}

Expand All @@ -142,5 +149,27 @@ protected override string GenerateFullPathToTool ()
{
return Path.Combine (ToolPath, ToolExe);
}

bool SupportsCSharp8 {
get {
// These are the values that pre-date C# 8. We assume any
// new value we encounter is something that supports it.
switch (LangVersion) {
case "7.3":
case "7.2":
case "7.1":
case "7":
case "6":
case "5":
case "4":
case "3":
case "ISO-2":
case "ISO-1":
return false;
}

return true;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -510,5 +510,63 @@ public void DesignTimeBuild (string classParser)
}
}
}

[Test]
[TestCaseSource (nameof (ClassParseOptions))]
public void BindDefaultInterfaceMethods (string classParser)
{
var proj = new XamarinAndroidBindingProject {
IsRelease = true,
};

// The sources for the .jar is in the jar itself.
string classesJarBase64 = @"
UEsDBBQACAgIANWk6UwAAAAAAAAAAAAAAAAJAAQATUVUQS1JTkYv/soAAAMAUEsHCAAAAAACAAAAAAA
AAFBLAwQUAAgICADVpOlMAAAAAAAAAAAAAAAAFAAAAE1FVEEtSU5GL01BTklGRVNULk1G803My0xLLS
7RDUstKs7Mz7NSMNQz4OVyLkpNLElN0XWqBAlY6BnEG5obKmj4FyUm56QqOOcXFeQXJZYA1WvycvFyA
QBQSwcIFGFrLUQAAABFAAAAUEsDBAoAAAgAAK2k6UwAAAAAAAAAAAAAAAAEAAAAY29tL1BLAwQKAAAI
AACtpOlMAAAAAAAAAAAAAAAADAAAAGNvbS94YW1hcmluL1BLAwQKAAAIAACwpOlMAAAAAAAAAAAAAAA
AEQAAAGNvbS94YW1hcmluL3Rlc3QvUEsDBBQACAgIAJmk6UwAAAAAAAAAAAAAAAAuAAAAY29tL3hhbW
FyaW4vdGVzdC9EZWZhdWx0SW50ZXJmYWNlTWV0aG9kcy5jbGFzc3WOvU7DMBSFjxsnKeWnXUE8QLrgh
ScAhBSJnwHE7qQ3JVUSC8dGFc/EwsrAA/BQiOuqLKnw8Pn4+LuWv38+vwCcY5biKMVUIKqMYWbzXEBe
mgUJTG/qju58W5B91EXDTbIkd6HtX3jj0G+DzPL5E28v3q8FJg/G25Ku6zB1ekWV9o3LO0e20iXdkns
2i/5spV+1QFaaVq11q23dKUe9U//4ArMwoRrdLdV9saLSJQICI4QVc4ogmTGfThBugFH0zuR/MpNNE7
x015NDL3C868VDL2XuYbL1joMTjI+BNpYC+/xcaA820uEvUEsHCIw1aijpAAAAhQEAAFBLAwQUAAgIC
ACYpOlMAAAAAAAAAAAAAAAAHAAAAERlZmF1bHRJbnRlcmZhY2VNZXRob2RzLmphdmF1zLEOwiAQBuCd
p7hRl0Zd2YyLgw9xwlGJFCocTWPTdxdSHarxxv///utR3bElUKFrRuwwWt8wJZZC9PnqrALrmaJBRXA
ig9nx+RNciG9BJzEJKKeXtnowIcBmCxNE4hw97CTMP6glPmJcuf1f91y5w7cbgtWQ3rCOBnSZymJhNX
nkPJYnUsziBVBLBwgzfz2miQAAAPUAAABQSwECFAAUAAgICADVpOlMAAAAAAIAAAAAAAAACQAEAAAAA
AAAAAAAAAAAAAAATUVUQS1JTkYv/soAAFBLAQIUABQACAgIANWk6UwUYWstRAAAAEUAAAAUAAAAAAAA
AAAAAAAAAD0AAABNRVRBLUlORi9NQU5JRkVTVC5NRlBLAQIKAAoAAAgAAK2k6UwAAAAAAAAAAAAAAAA
EAAAAAAAAAAAAAAAAAMMAAABjb20vUEsBAgoACgAACAAAraTpTAAAAAAAAAAAAAAAAAwAAAAAAAAAAA
AAAAAA5QAAAGNvbS94YW1hcmluL1BLAQIKAAoAAAgAALCk6UwAAAAAAAAAAAAAAAARAAAAAAAAAAAAA
AAAAA8BAABjb20veGFtYXJpbi90ZXN0L1BLAQIUABQACAgIAJmk6UyMNWoo6QAAAIUBAAAuAAAAAAAA
AAAAAAAAAD4BAABjb20veGFtYXJpbi90ZXN0L0RlZmF1bHRJbnRlcmZhY2VNZXRob2RzLmNsYXNzUEs
BAhQAFAAICAgAmKTpTDN/PaaJAAAA9QAAABwAAAAAAAAAAAAAAAAAgwIAAERlZmF1bHRJbnRlcmZhY2
VNZXRob2RzLmphdmFQSwUGAAAAAAcABwDOAQAAVgMAAAAA
";
proj.Jars.Add (new AndroidItem.EmbeddedJar ("dim.jar") {
BinaryContent = () => Convert.FromBase64String (classesJarBase64)
});

proj.AndroidClassParser = classParser;

proj.SetProperty ("EnableInterfaceMembersPreview", "True");
proj.SetProperty ("LangVersion", "preview");

using (var b = CreateDllBuilder (Path.Combine ("temp", TestName), false, false)) {
proj.NuGetRestore (b.ProjectDirectory);
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");

string asmpath = Path.GetFullPath (Path.Combine (Path.GetDirectoryName (new Uri (GetType ().Assembly.CodeBase).LocalPath), b.ProjectDirectory, b.Output.OutputPath, (proj.AssemblyName ?? proj.ProjectName) + ".dll"));
Assert.IsTrue (File.Exists (asmpath), "assembly does not exist");

var cs = b.Output.GetIntermediaryAsText (Path.Combine ("generated", "src", "Com.Xamarin.Test.IDefaultInterfaceMethods.cs"));
Assert.IsTrue (cs.Contains ("int Quux ();"), "Quux not generated.");
Assert.IsTrue (cs.Contains ("virtual unsafe int Foo ()"), "Foo not generated.");
Assert.IsTrue (cs.Contains ("virtual unsafe int Bar {"), "Bar not generated.");
Assert.IsTrue (cs.Contains ("set {"), "(Baz) setter not generated.");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ Copyright (C) 2012 Xamarin Inc. All rights reserved.
ToolPath="$(MonoAndroidToolsDirectory)"
ToolExe="$(BindingsGeneratorToolExe)"
UseShortFileNames="$(UseShortGeneratorFileNames)"
LangVersion="$(LangVersion)"
EnableInterfaceMembersPreview="$(EnableInterfaceMembersPreview)"
/>

<!-- Write a flag so we won't redo this target if nothing changed -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System;
using Com.Xamarin.Android;
using Java.Lang;
using NUnit.Framework;

namespace Xamarin.Android.JcwGenTests
{
[TestFixture]
public class DimTest
{
[Test]
public void TestDefaultInterfaceMethods ()
{
var empty = new EmptyOverrideClass ();
var iface = empty as IDefaultMethodsInterface;

Assert.AreEqual (0, iface.Foo ());
Assert.AreEqual (2, iface.Bar);
Assert.DoesNotThrow (() => iface.Bar = 5);

Assert.AreEqual (0, iface.InvokeFoo ());

Assert.Throws<UnsupportedOperationException> (() => iface.ToImplement ());
}

[Test]
public void TestOverriddenDefaultInterfaceMethods ()
{
var over = new ImplementedOverrideClass ();
var iface = over as IDefaultMethodsInterface;

Assert.AreEqual (6, over.Foo ());
Assert.AreEqual (100, over.Bar);
Assert.DoesNotThrow (() => over.Bar = 5);

Assert.AreEqual (6, iface.InvokeFoo ());
}

[Test]
public void TestManagedEmptyDefaultInterfaceMethods ()
{
// Test using empty C# implementing interface
var empty = new ManagedEmptyDefault ();
var iface = empty as IDefaultMethodsInterface;

Assert.AreEqual (0, iface.Foo ());

Assert.AreEqual (0, iface.InvokeFoo ());
}

[Test]
public void TestManagedOverriddenDefaultInterfaceMethods ()
{
// Test using method overridden in C#
var over = new ManagedOverrideDefault ();
var iface = over as IDefaultMethodsInterface;

Assert.AreEqual (15, over.Foo ());
Assert.AreEqual (15, iface.Foo ());

Assert.AreEqual (15, iface.InvokeFoo ());
}

[Test]
public void TestStaticMethods ()
{
Assert.AreEqual (10, IStaticMethodsInterface.Foo ());

Assert.AreEqual (3, IStaticMethodsInterface.Value);
Assert.DoesNotThrow (() => IStaticMethodsInterface.Value = 5);
}

[Test]
public void TestChainedDefaultInterfaceMethods ()
{
var over = new ImplementedChainOverrideClass ();
var iface = over as IDefaultMethodsInterface;

Assert.AreEqual (6, over.Foo ());
Assert.AreEqual (100, over.Bar);
Assert.DoesNotThrow (() => over.Bar = 5);

Assert.AreEqual (6, iface.InvokeFoo ());
}

class ManagedEmptyDefault : Java.Lang.Object, IDefaultMethodsInterface
{
}

class ManagedOverrideDefault : Java.Lang.Object, IDefaultMethodsInterface
{
public int Foo () => 15;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="Xamarin.Android.JcwGen_Tests">
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="22" />
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:label="Xamarin.Android.JcwGen-Tests">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
<AssemblyName>Xamarin.Android.JcwGen-Tests</AssemblyName>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<AndroidSupportedAbis>armeabi-v7a;x86</AndroidSupportedAbis>
<TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<AndroidUseLatestPlatformSdk>true</AndroidUseLatestPlatformSdk>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<Import Project="..\..\..\Configuration.props" />
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
Expand Down Expand Up @@ -51,6 +52,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BindingTests.cs" />
<Compile Include="DimBindingTests.cs" />
<Compile Include="ExceptionTests.cs" />
<Compile Include="MainActivity.cs" />
<Compile Include="TestInstrumentation.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
<AssemblyName>Xamarin.Android.McwGen-Tests</AssemblyName>
<AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
<AndroidClassParser>class-parse</AndroidClassParser>
<_JavacSourceVersion>1.8</_JavacSourceVersion>
<_JavacTargetVersion>1.8</_JavacTargetVersion>
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
<LangVersion>preview</LangVersion>
<EnableInterfaceMembersPreview>True</EnableInterfaceMembersPreview>
</PropertyGroup>
<Import Project="..\..\..\Configuration.props" />
<PropertyGroup>
Expand Down Expand Up @@ -113,6 +118,15 @@
<TestJarEntry Include="java\com\xamarin\android\Bxc37706Throwable.java">
<OutputFile>Jars/xamarin-test.jar</OutputFile>
</TestJarEntry>
<TestJarEntry Include="java\com\xamarin\android\DefaultMethodsInterface.java">
<OutputFile>Jars/xamarin-test.jar</OutputFile>
</TestJarEntry>
<TestJarEntry Include="java\com\xamarin\android\EmptyOverrideClass.java">
<OutputFile>Jars/xamarin-test.jar</OutputFile>
</TestJarEntry>
<TestJarEntry Include="java\com\xamarin\android\ImplementedOverrideClass.java">
<OutputFile>Jars/xamarin-test.jar</OutputFile>
</TestJarEntry>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
<Import Project="..\..\..\build-tools\scripts\Jar.targets" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.xamarin.android;

public interface DefaultMethodsInterface
{
default int foo () { return 0; }
default int getBar () { return 2; }
default void setBar (int value) { }
default int toImplement () { throw new UnsupportedOperationException (); }
default int invokeFoo () { return foo (); }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.xamarin.android;

public class EmptyOverrideClass implements DefaultMethodsInterface
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.xamarin.android;

public class ImplementedChainOverrideClass extends EmptyOverrideClass
{
@Override
public int foo () {
return 6;
}

@Override
public int getBar () {
return 100;
}

@Override
public void setBar (int value) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.xamarin.android;

public class ImplementedOverrideClass implements DefaultMethodsInterface
{
@Override
public int foo () {
return 6;
}

@Override
public int getBar () {
return 100;
}

@Override
public void setBar (int value) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.xamarin.android;

public interface StaticMethodsInterface
{
static int foo () { return 10; }
static int getValue () { return 3; }
static void setValue (int value) { }
}

0 comments on commit 2736e5b

Please sign in to comment.