Skip to content

Commit 71e3557

Browse files
committed
MarkIProtocolHandler
1 parent 0e0da79 commit 71e3557

File tree

14 files changed

+189
-17
lines changed

14 files changed

+189
-17
lines changed

dotnet/targets/Xamarin.Shared.Sdk.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@
734734
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(PrepareAssemblies)' != 'true'" Type="Xamarin.Linker.Steps.PreserveBlockCodeHandler" />
735735
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.OptimizeGeneratedCodeHandler" />
736736
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.BackingFieldDelayHandler" />
737-
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.MarkIProtocolHandler" />
737+
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(PrepareAssemblies)' != 'true'" Type="Xamarin.Linker.MarkIProtocolHandler" />
738738
<!-- MarkDispatcher substeps will run for all marked assemblies. -->
739739
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.Steps.MarkDispatcher" />
740740
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.Steps.PreserveSmartEnumConversionsHandler" />

msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ public class PrepareAssemblies : XamarinTask {
2424
public string MakeReproPath { get; set; } = "";
2525

2626
public string OutputDirectory { get; set; } = "";
27+
28+
[Required]
29+
public string Registrar { get; set; } = "";
2730
#endregion
2831

2932
#region Outputs
@@ -48,6 +51,7 @@ public override bool Execute ()
4851
var infos = InputAssemblies.Select (GetAssemblyInfo).ToArray ();
4952
using var preparer = new AssemblyPreparer (infos, Platform);
5053
preparer.MakeReproPath = MakeReproPath;
54+
preparer.Registrar = Registrar;
5155
var rv = preparer.Prepare (out var exceptions);
5256

5357
foreach (var pe in exceptions) {

tests/assembly-preparer/BaseClass.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ public void AssertPrepare (AssemblyPreparer preparer)
1010

1111
public void AssertPrepare (ApplePlatform platform, string code, out AssemblyDefinition assemblyDefinition)
1212
{
13-
AssertPrepare (platform, code, out assemblyDefinition);
13+
AssertPrepare (platform, RegistrarMode.Dynamic, code, out assemblyDefinition);
1414
}
1515

16-
public void AssertPrepare (ApplePlatform platform, string code, out AssemblyDefinition assemblyDefinition)
16+
public void AssertPrepare (ApplePlatform platform, RegistrarMode registrar, string code, out AssemblyDefinition assemblyDefinition)
1717
{
18-
AssertPrepareCode (platform, null, code, out string outputPath);
18+
AssertPrepareCode (platform, preparer => preparer.Registrar = registrar, code, out string outputPath);
1919
assemblyDefinition = AssemblyDefinition.ReadAssembly (outputPath);
2020
}
2121

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using Mono.Cecil.Rocks;
2+
3+
namespace AssemblyPreparerTests;
4+
5+
public class MarkIProtocolHandlerTests : BaseClass {
6+
[Test]
7+
[TestCase (ApplePlatform.MacCatalyst)]
8+
[TestCase (ApplePlatform.iOS)]
9+
[TestCase (ApplePlatform.TVOS)]
10+
[TestCase (ApplePlatform.MacOSX)]
11+
public void DynamicRegistrar (ApplePlatform platform)
12+
{
13+
var code = @"
14+
using System;
15+
using Foundation;
16+
using ObjCRuntime;
17+
18+
[Protocol]
19+
interface IProtocol {
20+
}
21+
22+
class MyClass : NSObject, IProtocol {
23+
}
24+
";
25+
26+
AssertPrepare (platform, RegistrarMode.Dynamic, code, out var assemblyDefinition);
27+
28+
var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "MyClass");
29+
var cctor = type.GetStaticConstructor ();
30+
var attribs = cctor.CustomAttributes?.OrderBy (v => string.Join (", ", v.ConstructorArguments.Select (v => v.Value?.ToString ()))).ToArray ();
31+
Assert.That (attribs, Is.Not.Null, "Attributes");
32+
Assert.That (attribs.Count, Is.EqualTo (1), "Attribute count");
33+
Assert.That (attribs.All (v => v.AttributeType.Name == "DynamicDependencyAttribute"), Is.True, "Attribute name");
34+
Assert.That ((string) attribs [0].ConstructorArguments [0].Value, Is.EqualTo ("IProtocol"), "First attribute's first argument");
35+
Assert.That (((TypeDefinition) attribs [0].ConstructorArguments [1].Value).FullName, Is.EqualTo ("MyClass"), "First attribute's second argument");
36+
}
37+
38+
[Test]
39+
[TestCase (ApplePlatform.MacCatalyst)]
40+
[TestCase (ApplePlatform.iOS)]
41+
[TestCase (ApplePlatform.TVOS)]
42+
[TestCase (ApplePlatform.MacOSX)]
43+
public void ManagedStaticRegistrar (ApplePlatform platform)
44+
{
45+
var code = @"
46+
using System;
47+
using Foundation;
48+
using ObjCRuntime;
49+
50+
[Protocol]
51+
interface IProtocol {
52+
}
53+
54+
class MyClass : NSObject, IProtocol {
55+
}
56+
";
57+
58+
AssertPrepare (platform, RegistrarMode.ManagedStatic, code, out var assemblyDefinition);
59+
60+
var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "MyClass");
61+
var cctor = type.GetStaticConstructor ();
62+
Assert.That (cctor, Is.Null, "No static constructor");
63+
}
64+
}

tests/assembly-preparer/ReproTest.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public void RoundTrip (ApplePlatform platform)
2121
Directory.Delete (reproPath); // the repro path can't exist prior to Prepare
2222
AssertPrepareCode (platform, (preparer) => {
2323
preparer.MakeReproPath = reproPath;
24+
preparer.Registrar = RegistrarMode.Dynamic;
2425
}, code, out string _);
2526
}
2627

tools/assembly-preparer/AssemblyPreparer.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ public class AssemblyPreparer : IDisposable {
1717

1818
public string MakeReproPath { get; set; } = string.Empty;
1919

20+
public RegistrarMode Registrar {
21+
get => configuration.Registrar;
22+
set => configuration.Registrar = value;
23+
}
24+
2025
public AssemblyPreparerInfo [] Assemblies { get; set; }
2126

2227
public AssemblyPreparer (AssemblyPreparerInfo [] assemblies, ApplePlatform platform)
@@ -42,6 +47,7 @@ bool SaveToReproPath (List<ProductException> exceptions)
4247
Directory.CreateDirectory (MakeReproPath);
4348
var lines = new List<string> ();
4449
lines.Add ($"Platform: {configuration.Platform}");
50+
lines.Add ($"Registrar: {configuration.Registrar}");
4551
foreach (var assembly in Assemblies) {
4652
lines.Add ($"Assembly: {Path.GetFileName (assembly.InputPath)}");
4753
File.Copy (assembly.InputPath, Path.Combine (MakeReproPath, Path.GetFileName (assembly.InputPath)));
@@ -69,6 +75,13 @@ public static AssemblyPreparer LoadFromReproPath (string reproPath)
6975
platform = Enum.Parse<ApplePlatform> (platformStr);
7076
#else
7177
platform = (ApplePlatform) Enum.Parse (typeof (ApplePlatform), platformStr);
78+
#endif
79+
} else if (line.StartsWith ("Registrar: ")) {
80+
var registrarStr = line.Substring ("Registrar: ".Length);
81+
#if NET
82+
registrar = Enum.Parse<RegistrarMode> (registrarStr);
83+
#else
84+
registrar = (RegistrarMode) Enum.Parse (typeof (RegistrarMode), registrarStr);
7285
#endif
7386
} else if (line.StartsWith ("Assembly: ")) {
7487
var assembly = line.Substring ("Assembly: ".Length);
@@ -90,13 +103,17 @@ public bool Prepare (out List<ProductException> exceptions)
90103
{
91104
exceptions = configuration.Exceptions;
92105

106+
if (Registrar == RegistrarMode.Default) {
107+
exceptions.Add (ErrorHelper.CreateError (99, "RegistrarMode must be explicitly set."));
108+
return false;
93109
}
94110

95111
if (!string.IsNullOrEmpty (MakeReproPath) && !SaveToReproPath (exceptions))
96112
return false;
97113

98114
var markHandlers = new IMarkHandler [] {
99115
new PreserveBlockCodeHandler (),
116+
new MarkIProtocolHandler (),
100117
};
101118

102119
var linkContext = new DerivedLinkContext (configuration);
@@ -109,12 +126,9 @@ public bool Prepare (out List<ProductException> exceptions)
109126

110127
// load assemblies
111128

112-
var assemblyResolver = new DefaultAssemblyResolver ();
113-
// var metadataResolver = new DefaultMetadataResolver ();
114-
115129
var parameters = new ReaderParameters {
116-
AssemblyResolver = assemblyResolver,
117-
// MetadataResolver = metadataResolver,
130+
AssemblyResolver = configuration.AssemblyResolver,
131+
MetadataResolver = configuration.MetadataResolver,
118132
ReadSymbols = true,
119133
SymbolReaderProvider = new DefaultSymbolReaderProvider (throwIfNoSymbol: false),
120134
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,46 @@
11
namespace Xamarin.Tuner;
22

3+
using Mono.Cecil;
4+
using Mono.CompilerServices.SymbolWriter;
35
using Mono.Linker;
6+
using Mono.Tuner;
47
using Xamarin.Bundler;
58

69
public class DerivedLinkContext : LinkContext {
10+
public RegistrarMode Registrar { get => Configuration.Registrar; }
11+
712
public DerivedLinkContext (LinkerConfiguration configuration) : base (configuration)
813
{
914
}
15+
16+
public IEnumerable<ICustomAttribute> GetCustomAttributes (ICustomAttributeProvider? provider, string @namespace, string name)
17+
{
18+
if (provider is null || !provider.HasCustomAttributes)
19+
yield break;
20+
21+
foreach (var attrib in provider.CustomAttributes) {
22+
if (attrib.AttributeType.Is (@namespace, name))
23+
yield return attrib;
24+
}
25+
}
26+
27+
/// <summary>
28+
/// Tries to resolve the TypeReference to a TypeDefinition
29+
/// </summary>
30+
public TypeDefinition? Resolve (TypeReference? typeReference)
31+
{
32+
if (typeReference is null)
33+
return null;
34+
35+
if (typeReference is TypeDefinition typeDefinition)
36+
return typeDefinition;
37+
38+
//
39+
// Types which never have TypeDefinition or can have ambiguous definition should not be passed in
40+
//
41+
if (typeReference is GenericParameter || (typeReference is TypeSpecification && typeReference is not GenericInstanceType))
42+
throw new NotSupportedException($"TypeDefinition cannot be resolved from '{typeReference.GetType()}' type");
43+
44+
return typeReference.Resolve ();
45+
}
1046
}

tools/assembly-preparer/Scaffolding/LinkContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public class LinkContext {
1414

1515
public LinkerConfiguration Configuration { get; private set; }
1616

17+
public LinkerConfiguration LinkerConfiguration { get => Configuration; }
18+
1719
public LinkContext (LinkerConfiguration configuration)
1820
{
1921
Configuration = configuration;

tools/assembly-preparer/Scaffolding/LinkerConfiguration.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ internal AppBundleRewriter AppBundleRewriter {
2525
}
2626
}
2727

28+
public IAssemblyResolver AssemblyResolver { get; private set; }
29+
public IMetadataResolver MetadataResolver { get; private set; }
30+
2831
DerivedLinkContext? derivedLinkContext;
2932
public DerivedLinkContext DerivedLinkContext {
3033
get {
@@ -47,6 +50,14 @@ public string PlatformAssembly {
4750
}
4851
}
4952

53+
public RegistrarMode Registrar { get; set; } = RegistrarMode.Default;
54+
55+
public LinkerConfiguration ()
56+
{
57+
AssemblyResolver = new DefaultAssemblyResolver ();
58+
MetadataResolver = new MetadataResolver (AssemblyResolver);
59+
}
60+
5061
public static LinkerConfiguration GetInstance (LinkContext context)
5162
{
5263
return context.Configuration;

tools/assembly-preparer/assembly-preparer.csproj

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,21 @@
2828
<Compile Include="../common/ErrorHelper.tools.cs">
2929
<Link>external/tools/common/ErrorHelper.tools.cs</Link>
3030
</Compile>
31+
<Compile Include="../common/NullableAttributes.cs">
32+
<Link>external/tools/common/NullableAttributes.cs</Link>
33+
</Compile>
34+
<Compile Include="../common/RegistrarMode.cs">
35+
<Link>external/tools/common/RegistrarMode.cs</Link>
36+
</Compile>
3137
<Compile Include="../dotnet-linker/AppBundleRewriter.cs">
3238
<Link>external/tools/dotnet-linker/AppBundleRewriter.cs</Link>
3339
</Compile>
40+
<Compile Include="../dotnet-linker/Extensions.cs">
41+
<Link>external/tools/dotnet-linker/Extensions.cs</Link>
42+
</Compile>
43+
<Compile Include="../dotnet-linker/MarkIProtocolHandler.cs">
44+
<Link>external/tools/dotnet-linker/MarkIProtocolHandler.cs</Link>
45+
</Compile>
3446
<Compile Include="../dotnet-linker/Steps/ConfigurationAwareMarkHandler.cs">
3547
<Link>external/tools/dotnet-linker/Steps/ConfigurationAwareMarkHandler.cs</Link>
3648
</Compile>
@@ -43,6 +55,15 @@
4355
<Compile Include="../linker/CustomSymbolWriter.cs">
4456
<Link>external/tools/linker/CustomSymbolWriter.cs</Link>
4557
</Compile>
58+
<Compile Include="../linker/MobileExtensions.cs">
59+
<Link>external/tools/linker/MobileExtensions.cs</Link>
60+
</Compile>
61+
<Compile Include="../linker/ObjCExtensions.cs">
62+
<Link>external/tools/linker/ObjCExtensions.cs</Link>
63+
</Compile>
64+
<Compile Include="../../src/ObjCRuntime/BindingImplAttribute.cs">
65+
<Link>external/src/ObjCRuntime/BindingImplAttribute.cs</Link>
66+
</Compile>
4667
<Compile Include="../../src/ObjCRuntime/ErrorHelper.cs">
4768
<Link>external/src/ObjCRuntime/ErrorHelper.cs</Link>
4869
</Compile>

0 commit comments

Comments
 (0)