122 строки
3.4 KiB
C#
122 строки
3.4 KiB
C#
|
//
|
||
|
// MonoTouchTypeMapStep.cs
|
||
|
//
|
||
|
// Authors:
|
||
|
// Sebastien Pouliot <sebastien@xamarin.com>
|
||
|
//
|
||
|
// Copyright 2012-2013 Xamarin Inc.
|
||
|
//
|
||
|
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
|
||
|
using Mono.Cecil;
|
||
|
using Mono.Linker.Steps;
|
||
|
using Mono.Tuner;
|
||
|
|
||
|
using Xamarin.Linker;
|
||
|
|
||
|
namespace MonoTouch.Tuner {
|
||
|
|
||
|
public class MonoTouchTypeMapStep : TypeMapStep {
|
||
|
|
||
|
static HashSet<TypeDefinition> cached_isnsobject;
|
||
|
static HashSet<TypeDefinition> needs_isdirectbinding_check;
|
||
|
static HashSet<MethodDefinition> generated_code;
|
||
|
|
||
|
public MonoTouchTypeMapStep ()
|
||
|
{
|
||
|
// FIXME: this won't work if we ever want to be able to run the linker for 32 and 64bit in parallel.
|
||
|
ObjCExtensions.cached_isnsobject = null;
|
||
|
Extensions.needs_isdirectbinding_check = null;
|
||
|
MobileExtensions.generated_code = null;
|
||
|
|
||
|
cached_isnsobject = new HashSet<TypeDefinition> ();
|
||
|
needs_isdirectbinding_check = new HashSet<TypeDefinition> ();
|
||
|
generated_code = new HashSet<MethodDefinition> ();
|
||
|
}
|
||
|
|
||
|
protected override void EndProcess ()
|
||
|
{
|
||
|
base.EndProcess ();
|
||
|
|
||
|
ObjCExtensions.cached_isnsobject = cached_isnsobject;
|
||
|
Extensions.needs_isdirectbinding_check = needs_isdirectbinding_check;
|
||
|
MobileExtensions.generated_code = generated_code;
|
||
|
}
|
||
|
|
||
|
protected override void MapType (TypeDefinition type)
|
||
|
{
|
||
|
base.MapType (type);
|
||
|
|
||
|
// we'll remove [GeneratedCode] in RemoveAttribute but we need this information later
|
||
|
// when processing Dispose methods in MonoTouchMarkStep
|
||
|
if (type.HasMethods) {
|
||
|
foreach (MethodDefinition m in type.Methods) {
|
||
|
if (m.IsGeneratedCode ())
|
||
|
generated_code.Add (m);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// additional checks for NSObject to check if the type is a *generated* bindings
|
||
|
// bonus: we cache, for every type, whether or not it inherits from NSObject (very useful later)
|
||
|
if (!IsNSObject (type))
|
||
|
return;
|
||
|
|
||
|
// if not, it's a user type, the IsDirectBinding check is required by all ancestors
|
||
|
if (!IsGeneratedBindings (type))
|
||
|
NeedsIsDirectBindingCheck (type);
|
||
|
#if DEBUG
|
||
|
else
|
||
|
Console.WriteLine ("{0} does NOT needs IsDirectBinding check", type);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// called once for each 'type' so it's a nice place to cache the result
|
||
|
// and ensure later steps re-use the same, pre-computed, result
|
||
|
static bool IsNSObject (TypeDefinition type)
|
||
|
{
|
||
|
if (!type.IsNSObject ())
|
||
|
return false;
|
||
|
cached_isnsobject.Add (type);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// type has a "public .ctor (IntPtr)" with a [CompilerGenerated] attribute
|
||
|
static bool IsGeneratedBindings (TypeDefinition type)
|
||
|
{
|
||
|
if (type.IsNested)
|
||
|
return IsGeneratedBindings (type.DeclaringType);
|
||
|
|
||
|
if (!type.HasMethods)
|
||
|
return false;
|
||
|
|
||
|
foreach (MethodDefinition m in type.Methods) {
|
||
|
if (!m.IsConstructor)
|
||
|
continue;
|
||
|
if (!m.HasParameters)
|
||
|
continue;
|
||
|
if (m.Parameters.Count != 1)
|
||
|
continue;
|
||
|
if (!m.Parameters [0].ParameterType.Is ("System", "IntPtr"))
|
||
|
continue;
|
||
|
return m.IsGeneratedCode ();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static void NeedsIsDirectBindingCheck (TypeDefinition type)
|
||
|
{
|
||
|
// all ancestors must be disallowed
|
||
|
// so we can short-circuit the recursion if we already have processed it
|
||
|
if (needs_isdirectbinding_check.Contains (type))
|
||
|
return;
|
||
|
|
||
|
needs_isdirectbinding_check.Add (type);
|
||
|
var base_type = type.BaseType;
|
||
|
if (base_type != null)
|
||
|
NeedsIsDirectBindingCheck (base_type.Resolve ());
|
||
|
}
|
||
|
}
|
||
|
}
|