예제 #1
0
        // get a name that is safe to use from ObjC code

        void GetSignatures(string objName, string monoName, MemberInfo info, ParameterInfo [] parameters, bool useTypeNames, bool isExtension, out string objcSignature, out string monoSignature)
        {
            var method = (info as MethodBase);             // else it's a PropertyInfo

            // special case for setter-only - the underscore looks ugly
            if ((method != null) && method.IsSpecialName)
            {
                objName = objName.Replace("_", String.Empty);
            }

            var objc = new StringBuilder(objName);
            var mono = new StringBuilder(monoName);

            mono.Append('(');

            for (int n = 0; n < parameters.Length; ++n)
            {
                ParameterInfo p = parameters [n];

                if (objc.Length > objName.Length)
                {
                    objc.Append(' ');
                    mono.Append(',');
                }

                string paramName = useTypeNames ? p.ParameterType.Name : p.Name;
                if ((method != null) && (n > 0 || !isExtension))
                {
                    if (n == 0)
                    {
                        bool mutatePropertyOrOperatorMethod = useTypeNames && (method.IsPropertyMethod() || method.IsOperatorMethod());
                        if (method.IsConstructor || mutatePropertyOrOperatorMethod || !method.IsSpecialName)
                        {
                            objc.Append(paramName.PascalCase());
                        }
                    }
                    else
                    {
                        objc.Append(paramName.ToLowerInvariant());
                    }
                }

                if (n > 0 || !isExtension)
                {
                    string ptname = NameGenerator.GetObjCParamTypeName(p, types);
                    objc.Append(":(").Append(ptname).Append(")").Append(NameGenerator.GetExtendedParameterName(p, parameters));
                }
                mono.Append(NameGenerator.GetMonoName(p.ParameterType));
            }

            mono.Append(')');

            objcSignature = objc.ToString();
            monoSignature = mono.ToString();
        }
        public EquatableHelper(ProcessedMethod method, SourceWriter headers, SourceWriter implementation) :
            base(method, headers, implementation)
        {
            ReturnType = "bool";
            var pt       = method.Method.GetParameters() [0].ParameterType;
            var objc     = NameGenerator.GetTypeName(pt);
            var nullable = !pt.IsPrimitive ? " * _Nullable" : "";

            ParameterType = pt;
            ObjCSignature = $"isEqualTo{objc.PascalCase ()}:({objc}{nullable})other";
            MonoSignature = $"Equals({NameGenerator.GetMonoName (pt)})";
        }
        protected override void Generate(ProcessedType type)
        {
            Type t           = type.Type;
            var  aname       = t.Assembly.GetName().Name.Sanitize();
            var  static_type = t.IsSealed && t.IsAbstract;

            var managed_name = NameGenerator.GetObjCName(t);

            List <string> conformed_protocols = new List <string> ();

            foreach (var i in t.GetInterfaces())
            {
                if (protocols.Contains(i))
                {
                    conformed_protocols.Add(NameGenerator.GetObjCName(i));
                }
            }

            var tbuilder = new ClassHelper(headers, implementation)
            {
                AssemblyQualifiedName = t.AssemblyQualifiedName,
                AssemblyName          = aname,
                BaseTypeName          = NameGenerator.GetTypeName(t.BaseType),
                Name            = NameGenerator.GetTypeName(t),
                Namespace       = t.Namespace,
                ManagedName     = t.Name,
                Protocols       = conformed_protocols,
                IsBaseTypeBound = types.Contains(t.BaseType),
                IsStatic        = t.IsSealed && t.IsAbstract,
                MetadataToken   = t.MetadataToken,
            };

            tbuilder.BeginHeaders();
            tbuilder.BeginImplementation();

            var default_init = false;
            List <ProcessedConstructor> constructors;

            if (ctors.TryGetValue(t, out constructors))
            {
                // First get the unavailable init ctor selectors in parent class
                var unavailableCtors = GetUnavailableParentCtors(t, constructors);
                if (unavailableCtors.Count() > 0)
                {
                    // TODO: Print a #pragma mark once we have a well defined header structure http://nshipster.com/pragma/
                    foreach (var uctor in unavailableCtors)
                    {
                        var    ctorparams = uctor.Constructor.GetParameters();
                        string name       = "init";
                        string signature  = ".ctor()";
                        if (ctorparams.Length > 0)
                        {
                            GetSignatures("initWith", uctor.Constructor.Name, uctor.Constructor, ctorparams, uctor.FallBackToTypeName, false, out name, out signature);
                        }
                        headers.WriteLine("/** This initializer is not available as it was not re-exposed from the base type");
                        headers.WriteLine(" *  For more details consult https://github.com/mono/Embeddinator-4000/blob/master/docs/ObjC.md#constructors-vs-initializers");
                        headers.WriteLine(" */");
                        headers.WriteLine($"- (nullable instancetype){name} NS_UNAVAILABLE;");
                        headers.WriteLine();
                    }
                }

                foreach (var ctor in constructors)
                {
                    var pcount = ctor.Constructor.ParameterCount;
                    default_init |= pcount == 0;

                    var    parameters = ctor.Constructor.GetParameters();
                    string name       = "init";
                    string signature  = ".ctor()";
                    if (parameters.Length > 0)
                    {
                        GetSignatures("initWith", ctor.Constructor.Name, ctor.Constructor, parameters, ctor.FallBackToTypeName, false, out name, out signature);
                    }

                    var builder = new MethodHelper(headers, implementation)
                    {
                        AssemblySafeName = aname,
                        ReturnType       = "nullable instancetype",
                        ManagedTypeName  = t.FullName,
                        MetadataToken    = ctor.Constructor.MetadataToken,
                        MonoSignature    = signature,
                        ObjCSignature    = name,
                        ObjCTypeName     = managed_name,
                        IsConstructor    = true,
                        IsValueType      = t.IsValueType,
                        IgnoreException  = true,
                    };

                    builder.WriteHeaders();

                    builder.BeginImplementation();
                    builder.WriteMethodLookup();

                    // TODO: this logic will need to be update for managed NSObject types (e.g. from XI / XM) not to call [super init]
                    implementation.WriteLine("if (!_object) {");
                    implementation.Indent++;
                    implementation.WriteLine($"MonoObject* __instance = mono_object_new (__mono_context.domain, {managed_name}_class);");

                    string postInvoke = String.Empty;
                    var    args       = "nil";
                    if (pcount > 0)
                    {
                        Generate(parameters, false, out postInvoke);
                        args = "__args";
                    }
                    builder.WriteInvoke(args);
                    implementation.Write(postInvoke);
                    implementation.WriteLine("_object = mono_embeddinator_create_object (__instance);");
                    implementation.Indent--;
                    implementation.WriteLine("}");
                    if (types.Contains(t.BaseType))
                    {
                        implementation.WriteLine("return self = [super initForSuper];");
                    }
                    else
                    {
                        implementation.WriteLine("return self = [super init];");
                    }
                    builder.EndImplementation();

                    headers.WriteLine();

                    if (members_with_default_values.Contains(ctor.Constructor))
                    {
                        default_init |= GenerateDefaultValuesWrappers(name, ctor.Constructor);
                    }
                }
            }

            // generate an `init` for a value type (even if none was defined, the default one is usable)
            if (!default_init && t.IsValueType)
            {
                var builder = new MethodHelper(headers, implementation)
                {
                    AssemblySafeName = aname,
                    ReturnType       = "nullable instancetype",
                    ManagedTypeName  = t.FullName,
                    MonoSignature    = ".ctor()",
                    ObjCSignature    = "init",
                    ObjCTypeName     = managed_name,
                    IsConstructor    = true,
                    IsValueType      = t.IsValueType,
                    IgnoreException  = true,
                };

                builder.WriteHeaders();
                builder.BeginImplementation();
                // no call to `WriteMethodLookup` since there is not such method if we reached this case

                implementation.WriteLine("if (!_object) {");
                implementation.Indent++;
                implementation.WriteLine($"MonoObject* __instance = mono_object_new (__mono_context.domain, {managed_name}_class);");
                // no call to `WriteInvoke` since there is not such method if we reached this case
                implementation.WriteLine("_object = mono_embeddinator_create_object (__instance);");
                implementation.Indent--;
                implementation.WriteLine("}");
                if (types.Contains(t.BaseType))
                {
                    implementation.WriteLine("return self = [super initForSuper];");
                }
                else
                {
                    implementation.WriteLine("return self = [super init];");
                }
                builder.EndImplementation();

                headers.WriteLine();
                default_init = true;
            }

            if (!default_init || static_type)
            {
                tbuilder.DefineNoDefaultInit();
            }

            List <ProcessedProperty> props;

            if (properties.TryGetValue(t, out props))
            {
                headers.WriteLine();
                foreach (var pi in props)
                {
                    Generate(pi);
                }
            }

            List <ProcessedFieldInfo> f;

            if (fields.TryGetValue(t, out f))
            {
                headers.WriteLine();
                foreach (var fi in f)
                {
                    Generate(fi);
                }
            }

            List <ProcessedProperty> s;

            if (subscriptProperties.TryGetValue(t, out s))
            {
                headers.WriteLine();
                foreach (var si in s)
                {
                    GenerateSubscript(si);
                }
            }

            List <ProcessedMethod> meths;

            if (methods.TryGetValue(t, out meths))
            {
                headers.WriteLine();
                foreach (var mi in meths)
                {
                    Generate(mi);
                }
            }

            MethodInfo m;

            if (icomparable.TryGetValue(t, out m))
            {
                var pt      = m.GetParameters() [0].ParameterType;
                var builder = new ComparableHelper(headers, implementation)
                {
                    ObjCSignature    = $"compare:({managed_name} * _Nullable)other",
                    AssemblySafeName = aname,
                    MetadataToken    = m.MetadataToken,
                    ObjCTypeName     = managed_name,
                    ManagedTypeName  = t.FullName,
                    MonoSignature    = $"CompareTo({NameGenerator.GetMonoName (pt)})",
                };
                builder.WriteHeaders();
                builder.WriteImplementation();
            }

            if (equals.TryGetValue(t, out m))
            {
                var builder = new EqualsHelper(headers, implementation)
                {
                    AssemblySafeName = aname,
                    MetadataToken    = m.MetadataToken,
                    ObjCTypeName     = managed_name,
                    ManagedTypeName  = t.FullName,
                };

                builder.WriteHeaders();
                builder.WriteImplementation();
            }

            if (hashes.TryGetValue(t, out m))
            {
                var builder = new HashHelper(headers, implementation)
                {
                    AssemblySafeName = aname,
                    MetadataToken    = m.MetadataToken,
                    ObjCTypeName     = managed_name,
                    ManagedTypeName  = t.FullName,
                };

                builder.WriteHeaders();
                builder.WriteImplementation();
            }

            tbuilder.EndHeaders();
            tbuilder.EndImplementation();
        }