ProcessedAssembly GetMscorlib(Type t)
        {
            var a = t.Assembly;

            if (a.GetName().Name != "mscorlib")
            {
                throw ErrorHelper.CreateError(99, "Internal error: incorrect assembly for `{t}`. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues)");
            }

            if (mscorlib_assembly == null)
            {
                mscorlib_assembly = new ProcessedAssembly(a)
                {
                    UserCode = false,
                };
            }
            return(mscorlib_assembly);
        }
Example #2
0
        public override void Process(IEnumerable <Assembly> input)
        {
            foreach (var a in input)
            {
                var pa = new ProcessedAssembly(a);
                // ignoring/warning one is not an option as they could be different (e.g. different builds/versions)
                if (!AddIfUnique(pa))
                {
                    throw ErrorHelper.CreateError(12, $"The assembly name `{pa.Name}` is not unique");
                }

                foreach (var t in GetTypes(a))
                {
                    if (t.IsEnum)
                    {
                        enums.Add(new ProcessedType(t));
                        continue;
                    }

                    if (t.IsInterface)
                    {
                        protocols.Add(new ProcessedType(t));
                    }
                    else
                    {
                        types.Add(new ProcessedType(t));
                    }

                    extension_type = t.HasCustomAttribute("System.Runtime.CompilerServices", "ExtensionAttribute");

                    implement_system_icomparable   = t.Implements("System", "IComparable");
                    implement_system_icomparable_t = t.Implements("System", "IComparable`1");

                    var constructors          = GetConstructors(t).OrderBy((arg) => arg.ParameterCount).ToList();
                    var processedConstructors = PostProcessConstructors(constructors).ToList();
                    if (processedConstructors.Count > 0)
                    {
                        ctors.Add(t, processedConstructors);
                    }

                    var typeEquals       = equals.Where(x => x.Key == t).Select(x => x.Value);
                    var meths            = GetMethods(t).OrderBy((arg) => arg.Name).ToList();
                    var processedMethods = PostProcessMethods(meths, typeEquals).ToList();
                    if (processedMethods.Count > 0)
                    {
                        methods.Add(t, processedMethods);
                    }

                    var props          = new List <PropertyInfo> ();
                    var subscriptProps = new List <PropertyInfo> ();
                    foreach (var pi in GetProperties(t))
                    {
                        var getter = pi.GetGetMethod();
                        var setter = pi.GetSetMethod();
                        // setter only property are valid in .NET and we need to generate a method in ObjC (there's no writeonly properties)
                        if (getter == null)
                        {
                            continue;
                        }

                        // indexers are implemented as methods and object subscripting
                        if ((getter.ParameterCount > 0) || ((setter != null) && setter.ParameterCount > 1))
                        {
                            subscriptProps.Add(pi);
                            continue;
                        }

                        // we can do better than methods for the more common cases (readonly and readwrite)
                        processedMethods.RemoveAll(x => x.Method == getter);
                        processedMethods.RemoveAll(x => x.Method == setter);
                        props.Add(pi);
                    }
                    props = props.OrderBy((arg) => arg.Name).ToList();
                    var processedProperties = PostProcessProperties(props).ToList();
                    if (processedProperties.Count > 0)
                    {
                        properties.Add(t, processedProperties);
                    }

                    if (subscriptProps.Count > 0)
                    {
                        if (subscriptProps.Count > 1)
                        {
                            delayed.Add(ErrorHelper.CreateWarning(1041, $"Indexed properties on {t.Name} is not generated because multiple indexed properties not supported."));
                        }
                        else
                        {
                            subscriptProperties.Add(t, PostProcessSubscriptProperties(subscriptProps).ToList());
                        }
                    }

                    // fields will need to be wrapped within properties
                    var f = GetFields(t).OrderBy((arg) => arg.Name).ToList();
                    var processedFields = PostProcessFields(f).ToList();
                    if (processedFields.Count > 0)
                    {
                        fields.Add(t, processedFields);
                    }
                }
            }
            types = types.OrderBy((arg) => arg.Type.FullName).OrderBy((arg) => types.Contains(arg.Type.BaseType)).ToList();
            Console.WriteLine($"\t{types.Count} types found");

            ErrorHelper.Show(delayed);
        }
        protected override void Generate(ProcessedAssembly a)
        {
            var originalName = a.Name;
            var name         = a.SafeName;

            implementation.WriteLine($"static void __lookup_assembly_{name} ()");
            implementation.WriteLine("{");
            implementation.Indent++;
            implementation.WriteLine($"if (__{name}_image)");
            implementation.Indent++;
            implementation.WriteLine("return;");
            implementation.Indent--;
            implementation.WriteLine("__initialize_mono ();");
            implementation.WriteLine($"__{name}_image = mono_embeddinator_load_assembly (&__mono_context, \"{originalName}.dll\");");
            implementation.WriteLine($"assert (__{name}_image && \"Could not load the assembly '{originalName}.dll'.\");");
            var categories = extensions_methods.Keys;

            if (categories.Count > 0)
            {
                implementation.WriteLine("// we cannot use `+initialize` inside categories as they would replace the original type code");
                implementation.WriteLine("// since there should not be tons of them we're pre-loading them when loading the assembly");
                foreach (var definedType in extensions_methods.Keys)
                {
                    var managed_name = NameGenerator.GetObjCName(definedType);
                    implementation.WriteLineUnindented("#if TOKENLOOKUP");
                    implementation.WriteLine($"{managed_name}_class = mono_class_get (__{name}_image, 0x{definedType.MetadataToken:X8});");
                    implementation.WriteLineUnindented("#else");
                    implementation.WriteLine($"{managed_name}_class = mono_class_from_name (__{name}_image, \"{definedType.Namespace}\", \"{definedType.Name}\");");
                    implementation.WriteLineUnindented("#endif");
                }
            }
            implementation.Indent--;
            implementation.WriteLine("}");
            implementation.WriteLine();

            var assembly = a.Assembly;

            foreach (var t in enums.Where((ProcessedType arg) => arg.Type.Assembly == assembly))
            {
                GenerateEnum(t);
            }

            foreach (var t in protocols.Where((ProcessedType arg) => arg.Type.Assembly == assembly))
            {
                GenerateProtocol(t);
            }

            foreach (var t in types.Where((ProcessedType arg) => arg.Type.Assembly == assembly))
            {
                Generate(t);
            }

            foreach (var extension in extensions_methods)
            {
                var defining_type = extension.Key;
                if (defining_type.Assembly != assembly)
                {
                    continue;
                }
                foreach (var category in extension.Value)
                {
                    GenerateCategory(defining_type, category.Key, category.Value);
                }
            }
        }