Ejemplo n.º 1
0
 public CSharpResolver(CSharpTypeResolveContext context)
 {
     if (context == null)
         throw new ArgumentNullException("context");
     this.compilation = context.Compilation;
     this.conversions = Conversions.Get(compilation);
     this.context = context;
     if (context.CurrentTypeDefinition != null)
         currentTypeDefinitionCache = new TypeDefinitionCache(context.CurrentTypeDefinition);
 }
Ejemplo n.º 2
0
		private CppResolver(ICompilation compilation, Conversions conversions, CppTypeResolveContext context, bool checkForOverflow, bool isWithinLambdaExpression, TypeDefinitionCache currentTypeDefinitionCache, ImmutableStack<IVariable> localVariableStack, ObjectInitializerContext objectInitializerStack)
		{
			this.compilation = compilation;
			this.conversions = conversions;
			this.context = context;
			this.checkForOverflow = checkForOverflow;
			this.isWithinLambdaExpression = isWithinLambdaExpression;
			this.currentTypeDefinitionCache = currentTypeDefinitionCache;
			this.localVariableStack = localVariableStack;
			this.objectInitializerStack = objectInitializerStack;
		}
Ejemplo n.º 3
0
        public static int Main(string [] args)
        {
            var resolver = new DirectoryAssemblyResolver(logger: Diagnostic.CreateConsoleLogger(), loadDebugSymbols: false);

            bool   help       = false;
            string outputPath = null;
            int    verbosity  = 0;

            var options = new OptionSet {
                "Usage: jcw-gen.exe OPTIONS* ASSEMBLY+ [@RESPONSE-FILES]",
                "",
                "Generates Java Callable Wrappers from specified assemblies.",
                "",
                "Copyright 2016 Xamarin Inc.",
                "",
                "Options:",
                { "L=",
                  "{DIRECTORY} to resolve assemblies from.",
                  v => resolver.SearchDirectories.Add(v) },
                { "o=",
                  "{DIRECTORY} to write Java source code to.",
                  v => outputPath = v },
                { "v:",
                  "Logging verbosity.",
                  (int?v) => verbosity = v.HasValue ? v.Value : verbosity + 1 },
                { "h|help|?",
                  "Show this message and exit",
                  v => help = v != null },
                new ResponseFileSource(),
            };
            var cache   = new TypeDefinitionCache();
            var scanner = new JavaTypeScanner(Diagnostic.CreateConsoleLogger(), cache);

            try {
                var assemblies = options.Parse(args);
                if (assemblies.Count == 0 || outputPath == null || help)
                {
                    int r = 0;
                    if (assemblies.Count == 0)
                    {
                        Console.Error.WriteLine("jcw-gen: No assemblies specified.");
                        r = 1;
                    }
                    else if (outputPath == null)
                    {
                        Console.Error.WriteLine("jcw-gen: No output directory specified. Use `jcw-gen -o PATH`.");
                        r = 1;
                    }
                    options.WriteOptionDescriptions(Console.Out);
                    return(r);
                }
                foreach (var assembly in assemblies)
                {
                    resolver.SearchDirectories.Add(Path.GetDirectoryName(assembly));
                    resolver.Load(assembly);
                }
                var types = scanner.GetJavaTypes(assemblies, resolver)
                            .Where(td => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(td, cache));
                foreach (var type in types)
                {
                    GenerateJavaCallableWrapper(type, outputPath, cache);
                }
                return(0);
            }
            catch (Exception e) {
                Console.Error.Write("jcw-gen: {0}", verbosity > 0 ? e.ToString() : e.Message);
                return(1);
            }
            finally {
                resolver.Dispose();
            }
        }
 public FixAbstractMethodsStep(DirectoryAssemblyResolver resolver, TypeDefinitionCache cache, TaskLoggingHelper logger)
     : base(cache)
 {
     this.resolver = resolver;
     this.logger   = logger;
 }
        bool CreateJavaSources(IEnumerable <TypeDefinition> javaTypes, TypeDefinitionCache cache)
        {
            string outputPath                = Path.Combine(OutputDirectory, "src");
            string monoInit                  = GetMonoInitSource(AndroidSdkPlatform);
            bool   hasExportReference        = ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll");
            bool   generateOnCreateOverrides = int.Parse(AndroidSdkPlatform) <= 10;

            bool ok = true;

            foreach (var t in javaTypes)
            {
                using (var writer = MemoryStreamPool.Shared.CreateStreamWriter()) {
                    try {
                        var jti = new JavaCallableWrapperGenerator(t, Log.LogWarning, cache)
                        {
                            GenerateOnCreateOverrides = generateOnCreateOverrides,
                            ApplicationJavaClass      = ApplicationJavaClass,
                            MonoRuntimeInitialization = monoInit,
                        };

                        jti.Generate(writer);
                        writer.Flush();

                        var path = jti.GetDestinationPath(outputPath);
                        MonoAndroidHelper.CopyIfStreamChanged(writer.BaseStream, path);
                        if (jti.HasExport && !hasExportReference)
                        {
                            Diagnostic.Error(4210, Properties.Resources.XA4210);
                        }
                    } catch (XamarinAndroidException xae) {
                        ok = false;
                        Log.LogError(
                            subcategory: "",
                            errorCode: "XA" + xae.Code,
                            helpKeyword: string.Empty,
                            file: xae.SourceFile,
                            lineNumber: xae.SourceLine,
                            columnNumber: 0,
                            endLineNumber: 0,
                            endColumnNumber: 0,
                            message: xae.MessageWithoutCode,
                            messageArgs: new object [0]
                            );
                    } catch (DirectoryNotFoundException ex) {
                        ok = false;
                        if (OS.IsWindows)
                        {
                            Diagnostic.Error(5301, Properties.Resources.XA5301, t.FullName, ex);
                        }
                        else
                        {
                            Diagnostic.Error(4209, Properties.Resources.XA4209, t.FullName, ex);
                        }
                    } catch (Exception ex) {
                        ok = false;
                        Diagnostic.Error(4209, Properties.Resources.XA4209, t.FullName, ex);
                    }
                }
            }
            return(ok);
        }
Ejemplo n.º 6
0
        private void AddToTypeCache(TypeDefinitionCache cache, string repositoryId, IList<ITypeDefinitionContainer> containers)
        {
            if (containers == null)
            {
                return;
            }

            foreach (ITypeDefinitionContainer container in containers)
            {
                cache.Put(repositoryId, container.TypeDefinition);
                AddToTypeCache(cache, repositoryId, container.Children);
            }
        }
Ejemplo n.º 7
0
        static Pipeline CreatePipeline(LinkerOptions options)
        {
            var cache    = new TypeDefinitionCache();
            var pipeline = new Pipeline();

            if (options.LinkNone)
            {
                pipeline.AppendStep(new FixAbstractMethodsStep(cache));
                if (options.AddKeepAlives)
                {
                    pipeline.AppendStep(new AddKeepAlivesStep(cache));
                }
                pipeline.AppendStep(new OutputStepWithTimestamps());
                return(pipeline);
            }

            pipeline.AppendStep(new LoadReferencesStep());

            if (options.I18nAssemblies != I18nAssemblies.None)
            {
                pipeline.AppendStep(new LoadI18nAssemblies(options.I18nAssemblies));
            }

            pipeline.AppendStep(new BlacklistStep());

            foreach (var desc in options.LinkDescriptions)
            {
                pipeline.AppendStep(new ResolveFromXmlStep(new XPathDocument(desc)));
            }

            pipeline.AppendStep(new CustomizeActions(options.LinkSdkOnly, options.SkippedAssemblies));

            pipeline.AppendStep(new TypeMapStep());

            // monodroid tuner steps
            pipeline.AppendStep(new SubStepDispatcher {
                new ApplyPreserveAttribute(),
            });
            pipeline.AppendStep(new SubStepDispatcher {
                new PreserveExportedTypes(),
                new RemoveSecurity(),
                new MarkJavaObjects(),
                new PreserveJavaExceptions(),
                new PreserveApplications(),
                new RemoveAttributes(),
                new PreserveDynamicTypes(),
                new PreserveHttpAndroidClientHandler {
                    HttpClientHandlerType = options.HttpClientHandlerType
                },
                new PreserveTlsProvider {
                    TlsProvider = options.TlsProvider
                },
                new PreserveSoapHttpClients(),
                new PreserveTypeConverters(),
                new PreserveLinqExpressions(),
                new PreserveRuntimeSerialization(),
            });

            pipeline.AppendStep(new PreserveCrypto());
            pipeline.AppendStep(new PreserveCode());

            pipeline.AppendStep(new RemoveResources(options.I18nAssemblies));               // remove collation tables
            // end monodroid specific

            pipeline.AppendStep(new FixAbstractMethodsStep(cache));
            pipeline.AppendStep(new MonoDroidMarkStep(cache));
            pipeline.AppendStep(new SweepStep());
            pipeline.AppendStep(new CleanStep());
            // monodroid tuner steps
            if (!string.IsNullOrWhiteSpace(options.ProguardConfiguration))
            {
                pipeline.AppendStep(new GenerateProguardConfiguration(options.ProguardConfiguration));
            }
            pipeline.AppendStep(new StripEmbeddedLibraries());
            if (options.AddKeepAlives)
            {
                pipeline.AppendStep(new AddKeepAlivesStep(cache));
            }

            if (options.LinkResources)
            {
                pipeline.AppendStep(new GetAssembliesStep());
                pipeline.AppendStep(new RemoveResourceDesignerStep());
            }
            // end monodroid specific
            pipeline.AppendStep(new RegenerateGuidStep());
            pipeline.AppendStep(new OutputStepWithTimestamps());

            return(pipeline);
        }
 public JavaCallableWrapperGenerator(TypeDefinition type, Action <string, object[]> log, TypeDefinitionCache cache)
     : this(type, null, log, cache)
 {
     if (type.HasNestedTypes)
     {
         children = new List <JavaCallableWrapperGenerator> ();
         AddNestedTypes(type);
     }
 }
Ejemplo n.º 9
0
 public MonoDroidMarkStep(TypeDefinitionCache cache)
 {
     this.cache = cache;
 }
Ejemplo n.º 10
0
        public TypeMover(AssemblyDefinition source, AssemblyDefinition destination, string destinationPath, Dictionary <string, System.Reflection.Emit.TypeBuilder> types, DirectoryAssemblyResolver resolver, TypeDefinitionCache cache)
        {
            Source          = source;
            Destination     = destination;
            DestinationPath = destinationPath;
            Types           = types;
            this.cache      = cache;

            if (App.Debug)
            {
                consoleWriteLine = GetSingleParameterMethod(resolver, Destination.MainModule, "mscorlib", "System.Console", "WriteLine", "System.String");
                if (consoleWriteLine == null)
                {
                    App.Warning("Unable to find System.Console::WriteLine method. Disabling debug injection");
                    App.Debug = false;
                }
            }
        }
Ejemplo n.º 11
0
        public static bool NeedsMarshalMethod(this MethodDefinition md, DirectoryAssemblyResolver resolver, TypeDefinitionCache cache, MethodInfo method, ref string name, ref string methodName, ref string signature)
        {
            var m = md;

            while (m != null)
            {
                if (CheckMethod(m, ref name, ref methodName, ref signature))
                {
                    return(true);
                }

                m = m.GetBaseDefinition(cache);

                if (m == md)
                {
                    break;
                }

                md = m;
            }

            foreach (var iface in method.DeclaringType.GetInterfaces())
            {
                if (iface.IsGenericType)
                {
                    continue;
                }

                var ifaceMap = method.DeclaringType.GetInterfaceMap(iface);
                var ad       = resolver.GetAssembly(iface.Assembly.Location);
                var id       = ad.MainModule.GetType(iface.GetCecilName());

                if (id == null)
                {
                    App.Warning($"Couln't find iterface {iface.FullName}");
                    continue;
                }

                for (int i = 0; i < ifaceMap.TargetMethods.Length; i++)
                {
                    if (ifaceMap.TargetMethods [i] == method)
                    {
                        var imd = id.GetMethodDefinition(ifaceMap.InterfaceMethods [i]);

                        if (CheckMethod(imd, ref name, ref methodName, ref signature))
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
 public FixAbstractMethodsStep(TypeDefinitionCache cache)
 {
     this.cache = cache;
 }
Ejemplo n.º 13
0
        public static bool TryGetBaseOrInterfaceRegisterMember(this MethodDefinition method, TypeDefinitionCache cache, out string member, out string nativeMethod, out string signature)
        {
            var type = method.DeclaringType;

            member = nativeMethod = signature = null;

            if (method.IsConstructor || type == null || !type.HasNestedTypes)
            {
                return(false);
            }

            var m = method.GetBaseDefinition(cache);

            while (m != null)
            {
                if (m == method)
                {
                    break;
                }

                method = m;

                if (m.TryGetRegisterMember(out member, out nativeMethod, out signature))
                {
                    return(true);
                }

                m = m.GetBaseDefinition(cache);
            }

            if (!method.DeclaringType.HasInterfaces || !method.IsNewSlot)
            {
                return(false);
            }

            foreach (var iface in method.DeclaringType.Interfaces)
            {
                if (iface.InterfaceType.IsGenericInstance)
                {
                    continue;
                }

                var itype = iface.InterfaceType.Resolve();
                if (itype == null || !itype.HasMethods)
                {
                    continue;
                }

                foreach (var im in itype.Methods)
                {
                    if (im.IsEqual(method, cache))
                    {
                        return(im.TryGetRegisterMember(out member, out nativeMethod, out signature));
                    }
                }
            }

            return(false);
        }
        private void WriteXml(XmlWriter writer, object o, TypeDefinition type, string name = null, bool writeReservedObject = false)
        {
            if (type.IsPrimitive)
            {
                WriteXmlPrimitive(o, writer, type, name);
                return;
            }
            if (type.IsDictionary)
            {
                WriteXmlDictionary(o, writer, type, name);
                return;
            }
            if (type.IsArray || type.IsEnumerable)
            {
                WriteXmlArray(o, writer, type, name);
                return;
            }
            writer.WriteStartElement(name ?? type.Name);
            writer.WriteAttributeString("type", type.FullName);

            // Get configuration for type
            var configuration = GetConfiguration(type.Type);

            if (configuration != null)
            {
                if (configuration.IsObjectReference)
                {
                    var objectId = configuration.GetObjectId(o);

                    var key = type.FullName + "_" + objectId;
                    if (writeReservedObject && _reservedReferencesObjects.ContainsKey(key))
                    {
                        _reservedReferencesObjects.Remove(key);
                    }
                    else if (_referencesObjects.ContainsKey(key) || _reservedReferencesObjects.ContainsKey(key))
                    {
                        writer.WriteAttributeString("ref", objectId);
                        writer.WriteEndElement();
                        return;
                    }
                    writer.WriteAttributeString("id", objectId);
                    _referencesObjects.Add(key, o);
                }

                if (configuration.Version > 0)
                {
                    writer.WriteAttributeString("ver",
                                                configuration.Version.ToString(CultureInfo.InvariantCulture));
                }
                if (configuration.IsCustomSerializer)
                {
                    configuration.WriteObject(writer, o);
                    writer.WriteEndElement();
                    return;
                }
            }

            var properties = type.Properties;

            foreach (var propertyInfo in properties)
            {
                var propertyValue = propertyInfo.GetValue(o);
                if (propertyValue == null)
                {
                    continue;
                }

                var defType = TypeDefinitionCache.GetDefinition(propertyValue.GetType());

                if (defType.IsObjectToSerialize || defType.IsArray || defType.IsEnumerable)
                {
                    WriteXml(writer, propertyValue, defType, propertyInfo.Name);
                }
                else if (defType.IsEnum)
                {
                    writer.WriteStartElement(propertyInfo.Name);
                    writer.WriteString(propertyValue.ToString());
                    writer.WriteEndElement();
                }
                else
                {
                    bool toEncrypt = false;
                    if (configuration != null)
                    {
                        if (configuration.CheckPropertyEncryption(propertyInfo.Name))
                        {
                            toEncrypt = true;
                        }
                    }

                    WriteXmlPrimitive(propertyValue, writer, defType, propertyInfo.Name, toEncrypt);
                }
            }
            writer.WriteEndElement();
        }
        private object ReadXml(XElement currentNode, TypeDefinition type, object instance = null)
        {
            if (type.IsPrimitive)
            {
                return(PrimitiveValueTools.GetPrimitiveValue(currentNode.Value, type, currentNode.Name.LocalName));
            }
            if (type.IsDictionary)
            {
                return(ReadXmlDictionary(currentNode, type));
            }

            if (type.IsArray || type.IsEnumerable)
            {
                return(ReadXmlArray(currentNode, type));
            }

            if (currentNode == null)
            {
                return(null);
            }

            TypeDefinition currentNodeDef = null;
            // Retrieve type from XML (Property can be base type. In xml can be saved inherited object)
            var typeAttribute = currentNode.Attribute("type");

            if (typeAttribute != null)
            {
                var currentNodeType = TypeDefinitionCache.GetType(typeAttribute.Value);
                currentNodeDef = TypeDefinitionCache.GetDefinition(currentNodeType);
            }
            // If xml does not contain type get property type
            if (currentNodeDef == null)
            {
                currentNodeDef = type;
            }

            // Get configuration for type
            var configuration = GetConfiguration(currentNodeDef.Type);

            if (configuration != null)
            {
                // Run migrator if exists
                if (configuration.Version > 0)
                {
                    configuration.Map(currentNodeDef.Type, currentNode);
                }
                // run custom serializer if exists
                if (configuration.IsCustomSerializer)
                {
                    return(configuration.ReadObject(currentNode));
                }
            }

            // Create new instance if not exists
            var currentObject = instance ?? currentNodeDef.ObjectActivator();

            if (configuration != null)
            {
                if (configuration.IsObjectReference)
                {
                    string refId = currentNode.Attribute("ref")?.Value;
                    if (!string.IsNullOrEmpty(refId))
                    {
                        var key = currentNodeDef.FullName + "_" + refId;
                        if (_referencesObjects.ContainsKey(key))
                        {
                            return(_referencesObjects[key]);
                        }
                        _referencesObjects.Add(key, currentObject);
                    }
                    string objectId = currentNode.Attribute("id")?.Value;
                    if (!string.IsNullOrEmpty(objectId))
                    {
                        var key = currentNodeDef.FullName + "_" + objectId;
                        if (_referencesObjects.ContainsKey(key))
                        {
                            currentObject = _referencesObjects[key];
                        }
                        else
                        {
                            _referencesObjects.Add(key, currentObject);
                        }
                    }
                }
            }

            // Read all elements
            foreach (var xElement in currentNode.Elements())
            {
                var localName    = xElement.Name.LocalName;
                var value        = xElement.Value;
                var propertyInfo = type.GetProperty(localName);
                if (propertyInfo == null)
                {
                    throw new InvalidOperationException("Missing property " + currentNode.Name.LocalName + "\\" + localName);
                }
                var propertyDef = TypeDefinitionCache.GetDefinition(propertyInfo.Type);
                if (xElement.HasAttributes && xElement.Attribute("type") != null)
                {
                    // If type of property is saved in xml, we need check type of object actual assigned to property. There may be a base type.
                    Type targetType    = TypeDefinitionCache.GetType(xElement.Attribute("type").Value);
                    var  targetTypeDef = TypeDefinitionCache.GetDefinition(targetType);
                    var  obj           = propertyInfo.GetValue(currentObject);
                    if (obj == null || obj.GetType() != targetType)
                    {
                        obj = targetTypeDef.ObjectActivator();
                    }
                    var obj2 = ReadXml(xElement, targetTypeDef, obj);
                    propertyInfo.SetValue(currentObject, obj2);
                }
                else if (propertyDef.IsObjectToSerialize || propertyDef.IsArray || propertyDef.IsEnumerable || propertyDef.IsDictionary)
                {
                    //If xml does not contain type but we known that it is object
                    var obj  = propertyInfo.GetValue(currentObject);
                    var obj2 = ReadXml(xElement, propertyDef, obj);
                    propertyInfo.SetValue(currentObject, obj2);
                }
                else
                {
                    if (string.IsNullOrEmpty(value))
                    {
                        continue;
                    }

                    if (configuration != null)
                    {
                        if (configuration.CheckPropertyEncryption(propertyInfo.Name))
                        {
                            var algorithm = GetEncryptionAlgorithm();
                            if (algorithm != null)
                            {
                                value = algorithm.Decrypt(value);
                            }
                        }
                    }

                    object primitive = PrimitiveValueTools.GetPrimitiveValue(value, propertyDef, xElement.Name.LocalName);
                    propertyInfo.SetValue(currentObject, primitive);
                }
            }
            return(currentObject);
        }
Ejemplo n.º 16
0
        static void GenerateJavaCallableWrapper(TypeDefinition type, string outputPath, TypeDefinitionCache cache)
        {
            var generator = new JavaCallableWrapperGenerator(type, log: Console.WriteLine, cache)
            {
            };

            generator.Generate(outputPath);
        }
        JavaCallableWrapperGenerator(TypeDefinition type, string outerType, Action <string, object[]> log, TypeDefinitionCache cache)
        {
            this.type  = type;
            this.log   = log;
            this.cache = cache ?? new TypeDefinitionCache();

            if (type.IsEnum || type.IsInterface || type.IsValueType)
            {
                Diagnostic.Error(4200, LookupSource(type), Localization.Resources.JavaCallableWrappers_XA4200, type.FullName);
            }

            string jniName = JavaNativeTypeManager.ToJniName(type);

            if (jniName == null)
            {
                Diagnostic.Error(4201, LookupSource(type), Localization.Resources.JavaCallableWrappers_XA4201, type.FullName);
            }
            if (!string.IsNullOrEmpty(outerType))
            {
                string p;
                jniName = jniName.Substring(outerType.Length + 1);
                ExtractJavaNames(outerType, out p, out outerType);
            }
            ExtractJavaNames(jniName, out package, out name);
            if (string.IsNullOrEmpty(package) &&
                (type.IsSubclassOf("Android.App.Activity", cache) ||
                 type.IsSubclassOf("Android.App.Application", cache) ||
                 type.IsSubclassOf("Android.App.Service", cache) ||
                 type.IsSubclassOf("Android.Content.BroadcastReceiver", cache) ||
                 type.IsSubclassOf("Android.Content.ContentProvider", cache)))
            {
                Diagnostic.Error(4203, LookupSource(type), Localization.Resources.JavaCallableWrappers_XA4203, jniName);
            }

            foreach (MethodDefinition minfo in type.Methods.Where(m => !m.IsConstructor))
            {
                var baseRegisteredMethod = GetBaseRegisteredMethod(minfo);
                if (baseRegisteredMethod != null)
                {
                    AddMethod(baseRegisteredMethod, minfo);
                }
                else if (GetExportFieldAttributes(minfo).Any())
                {
                    AddMethod(null, minfo);
                    HasExport = true;
                }
                else if (GetExportAttributes(minfo).Any())
                {
                    AddMethod(null, minfo);
                    HasExport = true;
                }
            }

            foreach (MethodDefinition imethod in type.Interfaces.Select(ifaceInfo => ifaceInfo.InterfaceType)
                     .Select(r => {
                var d = r.Resolve();
                if (d == null)
                {
                    Diagnostic.Error(4204,
                                     LookupSource(type),
                                     Localization.Resources.JavaCallableWrappers_XA4204,
                                     r.FullName);
                }
                return(d);
            })
                     .Where(d => GetRegisterAttributes(d).Any())
                     .SelectMany(d => d.Methods)
                     .Where(m => !m.IsStatic))
            {
                AddMethod(imethod, imethod);
            }

            var ctorTypes = new List <TypeDefinition> ()
            {
                type,
            };

            foreach (var bt in type.GetBaseTypes(cache))
            {
                ctorTypes.Add(bt);
                RegisterAttribute rattr = GetRegisterAttributes(bt).FirstOrDefault();
                if (rattr != null && rattr.DoNotGenerateAcw)
                {
                    break;
                }
            }
            ctorTypes.Reverse();

            var curCtors = new List <MethodDefinition> ();

            foreach (MethodDefinition minfo in type.Methods.Where(m => m.IsConstructor))
            {
                if (GetExportAttributes(minfo).Any())
                {
                    if (minfo.IsStatic)
                    {
                        // Diagnostic.Warning (log, "ExportAttribute does not work on static constructor");
                    }
                    else
                    {
                        AddConstructor(minfo, ctorTypes [0], outerType, null, curCtors, false, true);
                        HasExport = true;
                    }
                }
            }

            AddConstructors(ctorTypes [0], outerType, null, curCtors, true);

            for (int i = 1; i < ctorTypes.Count; ++i)
            {
                var baseCtors = curCtors;
                curCtors = new List <MethodDefinition> ();
                AddConstructors(ctorTypes [i], outerType, baseCtors, curCtors, false);
            }
        }
Ejemplo n.º 18
0
        public bool Generate(bool debugBuild, bool skipJniAddNativeMethodRegistrationAttributeScan, List <TypeDefinition> javaTypes, TypeDefinitionCache cache, string outputDirectory, bool generateNativeAssembly, out ApplicationConfigTaskState appConfState)
        {
            if (String.IsNullOrEmpty(outputDirectory))
            {
                throw new ArgumentException("must not be null or empty", nameof(outputDirectory));
            }

            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }

            appConfState = new ApplicationConfigTaskState {
                JniAddNativeMethodRegistrationAttributePresent = skipJniAddNativeMethodRegistrationAttributeScan
            };

            string typemapsOutputDirectory = Path.Combine(outputDirectory, "typemaps");

            if (debugBuild)
            {
                return(GenerateDebug(skipJniAddNativeMethodRegistrationAttributeScan, javaTypes, cache, typemapsOutputDirectory, generateNativeAssembly, appConfState));
            }

            return(GenerateRelease(skipJniAddNativeMethodRegistrationAttributeScan, javaTypes, typemapsOutputDirectory, appConfState));
        }
            public Signature(MethodDefinition method, ExportFieldAttribute exportField, TypeDefinitionCache cache)
                : this(method.Name, GetJniSignature(method, cache), "__export__", null, null, null)
            {
                if (method.HasParameters)
                {
                    Diagnostic.Error(4205, JavaCallableWrapperGenerator.LookupSource(method), Localization.Resources.JavaCallableWrappers_XA4205);
                }
                if (method.ReturnType.MetadataType == MetadataType.Void)
                {
                    Diagnostic.Error(4208, JavaCallableWrapperGenerator.LookupSource(method), Localization.Resources.JavaCallableWrappers_XA4208);
                }
                IsExport   = true;
                IsStatic   = method.IsStatic;
                JavaAccess = JavaCallableWrapperGenerator.GetJavaAccess(method.Attributes & MethodAttributes.MemberAccessMask);

                // annotations are processed within JavaFieldInfo, not the initializer method. So we don't generate them here.
            }
Ejemplo n.º 20
0
 bool GenerateDebug(bool skipJniAddNativeMethodRegistrationAttributeScan, List <TypeDefinition> javaTypes, TypeDefinitionCache cache, string outputDirectory, bool generateNativeAssembly, ApplicationConfigTaskState appConfState)
 {
     if (generateNativeAssembly)
     {
         return(GenerateDebugNativeAssembly(skipJniAddNativeMethodRegistrationAttributeScan, javaTypes, cache, outputDirectory, appConfState));
     }
     return(GenerateDebugFiles(skipJniAddNativeMethodRegistrationAttributeScan, javaTypes, cache, outputDirectory, appConfState));
 }
Ejemplo n.º 21
0
        static void Run(CodeGeneratorOptions options, DirectoryAssemblyResolver resolver)
        {
            string assemblyQN              = options.AssemblyQualifiedName;
            string api_level               = options.ApiLevel;
            int    product_version         = options.ProductVersion;
            bool   preserve_enums          = options.PreserveEnums;
            string csdir                   = options.ManagedCallableWrapperSourceOutputDirectory ?? "cs";
            string javadir                 = "java";
            string enumdir                 = options.EnumOutputDirectory ?? "enum";
            string enum_metadata           = options.EnumMetadataOutputFile ?? "enummetadata";
            var    references              = options.AssemblyReferences;
            string enum_fields_map         = options.EnumFieldsMapFile;
            string enum_flags              = options.EnumFlagsFile;
            string enum_methods_map        = options.EnumMethodsMapFile;
            var    fixups                  = options.FixupFiles;
            var    annotations_zips        = options.AnnotationsZipFiles;
            string filename                = options.ApiDescriptionFile;
            string mapping_file            = options.MappingReportFile;
            bool   only_xml_adjuster       = options.OnlyRunApiXmlAdjuster;
            string api_xml_adjuster_output = options.ApiXmlAdjusterOutput;
            var    apiSource               = "";
            var    opt = new CodeGenerationOptions()
            {
                CodeGenerationTarget           = options.CodeGenerationTarget,
                UseGlobal                      = options.GlobalTypeNames,
                IgnoreNonPublicType            = true,
                UseShortFileNames              = options.UseShortFileNames,
                ProductVersion                 = options.ProductVersion,
                SupportInterfaceConstants      = options.SupportInterfaceConstants,
                SupportDefaultInterfaceMethods = options.SupportDefaultInterfaceMethods,
                SupportNestedInterfaceTypes    = options.SupportNestedInterfaceTypes,
                SupportNullableReferenceTypes  = options.SupportNullableReferenceTypes,
            };
            var resolverCache = new TypeDefinitionCache();

            // Load reference libraries

            foreach (var lib in options.LibraryPaths)
            {
                resolver.SearchDirectories.Add(lib);
            }
            foreach (var reference in references)
            {
                resolver.SearchDirectories.Add(Path.GetDirectoryName(reference));
            }

            // Figure out if this is class-parse
            string apiXmlFile    = filename;
            string apiSourceAttr = null;

            using (var xr = XmlReader.Create(filename)) {
                xr.MoveToContent();
                apiSourceAttr = xr.GetAttribute("api-source");
            }

            // We don't use shallow referenced types with class-parse because the Adjuster process
            // enumerates every ctor/method/property/field to build its model, so we will need
            // every type to be fully populated.
            opt.UseShallowReferencedTypes = apiSourceAttr != "class-parse";

            foreach (var reference in references.Distinct())
            {
                try {
                    Report.Verbose(0, "resolving assembly {0}.", reference);
                    var assembly = resolver.Load(reference);
                    foreach (var md in assembly.Modules)
                    {
                        foreach (var td in md.Types)
                        {
                            // FIXME: at some stage we want to import generic types.
                            // For now generator fails to load generic types that have conflicting type e.g.
                            // AdapterView`1 and AdapterView cannot co-exist.
                            // It is mostly because generator primarily targets jar (no real generics land).
                            var nonGenericOverload = td.HasGenericParameters
                                                                ? md.GetType(td.FullName.Substring(0, td.FullName.IndexOf('`')))
                                                                : null;
                            if (BindSameType(td, nonGenericOverload, resolverCache))
                            {
                                continue;
                            }
                            ProcessReferencedType(td, opt);
                        }
                    }
                } catch (Exception ex) {
                    Report.Warning(0, Report.WarningCodeGenerator + 0, ex, "failed to parse assembly {0}: {1}", reference, ex.Message);
                }
            }

            // For class-parse API description, transform it to jar2xml style.
            if (apiSourceAttr == "class-parse")
            {
                apiXmlFile = api_xml_adjuster_output ?? Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename) + ".adjusted");
                new Adjuster().Process(filename, opt, opt.SymbolTable.AllRegisteredSymbols(opt).OfType <GenBase> ().ToArray(), apiXmlFile, Report.Verbosity ?? 0);
            }
            if (only_xml_adjuster)
            {
                return;
            }

            // load XML API definition with fixups.

            Dictionary <string, EnumMappings.EnumDescription> enums = null;

            EnumMappings enummap = null;

            if (enum_fields_map != null || enum_methods_map != null)
            {
                enummap = new EnumMappings(enumdir, enum_metadata, api_level, preserve_enums);
                enums   = enummap.Process(enum_fields_map, enum_flags, enum_methods_map);
                fixups.Add(enum_metadata);
            }

            Parser         p    = new Parser(opt);
            List <GenBase> gens = p.Parse(apiXmlFile, fixups, api_level, product_version);

            if (gens == null)
            {
                return;
            }
            apiSource = p.ApiSource;

            // disable interface default methods here, especially before validation.
            gens = gens.Where(g => !g.IsObfuscated && g.Visibility != "private").ToList();
            foreach (var gen in gens)
            {
                gen.StripNonBindables(opt);
                if (gen.IsGeneratable)
                {
                    AddTypeToTable(opt, gen);
                }
            }

            // Apply fixups
            KotlinFixups.Fixup(gens);

            Validate(gens, opt, new CodeGeneratorContext());

            foreach (var api_versions_xml in options.ApiVersionsXmlFiles)
            {
                ApiVersionsSupport.AssignApiLevels(gens, api_versions_xml);
            }

            foreach (GenBase gen in gens)
            {
                gen.FillProperties();
            }

            var cache = new AncestorDescendantCache(gens);

            foreach (var gen in gens)
            {
                gen.UpdateEnums(opt, cache);
            }

            foreach (GenBase gen in gens)
            {
                gen.FixupMethodOverrides(opt);
            }

            foreach (GenBase gen in gens)
            {
                gen.FixupExplicitImplementation();
            }

            SealedProtectedFixups.Fixup(gens);

            GenerateAnnotationAttributes(gens, annotations_zips);

            //SymbolTable.Dump ();

            GenerationInfo gen_info = new GenerationInfo(csdir, javadir, assemblyQN);

            opt.AssemblyName = gen_info.Assembly;

            if (mapping_file != null)
            {
                GenerateMappingReportFile(gens, mapping_file);
            }

            new NamespaceMapping(gens).Generate(opt, gen_info);

            foreach (IGeneratable gen in gens)
            {
                if (gen.IsGeneratable)
                {
                    gen.Generate(opt, gen_info);
                }
            }


            ClassGen.GenerateTypeRegistrations(opt, gen_info);
            ClassGen.GenerateEnumList(gen_info);

            // Create the .cs files for the enums
            var enumFiles = enums == null
                                ? null
                                : enummap.WriteEnumerations(enumdir, enums, FlattenNestedTypes(gens).ToArray(), opt.UseShortFileNames);

            gen_info.GenerateLibraryProjectFile(options, enumFiles);
        }
Ejemplo n.º 22
0
        bool GenerateDebugFiles(bool skipJniAddNativeMethodRegistrationAttributeScan, List <TypeDefinition> javaTypes, TypeDefinitionCache cache, string outputDirectory, ApplicationConfigTaskState appConfState)
        {
            var modules = new Dictionary <string, ModuleDebugData> (StringComparer.Ordinal);
            int maxModuleFileNameWidth = 0;
            int maxModuleNameWidth     = 0;

            var javaDuplicates = new Dictionary <string, List <TypeMapDebugEntry> > (StringComparer.Ordinal);

            foreach (TypeDefinition td in javaTypes)
            {
                UpdateApplicationConfig(td, appConfState);
                string          moduleName = td.Module.Assembly.Name.Name;
                ModuleDebugData module;

                if (!modules.TryGetValue(moduleName, out module))
                {
                    string outputFileName = $"{moduleName}{TypemapExtension}";
                    module = new ModuleDebugData {
                        EntryCount       = 0,
                        JavaNameWidth    = 0,
                        ManagedNameWidth = 0,
                        JavaToManagedMap = new List <TypeMapDebugEntry> (),
                        ManagedToJavaMap = new List <TypeMapDebugEntry> (),
                        OutputFilePath   = Path.Combine(outputDirectory, outputFileName),
                        ModuleName       = moduleName,
                        ModuleNameBytes  = outputEncoding.GetBytes(moduleName),
                    };

                    if (module.ModuleNameBytes.Length > maxModuleNameWidth)
                    {
                        maxModuleNameWidth = module.ModuleNameBytes.Length;
                    }

                    if (outputFileName.Length > maxModuleFileNameWidth)
                    {
                        maxModuleFileNameWidth = outputFileName.Length;
                    }

                    modules.Add(moduleName, module);
                }

                TypeMapDebugEntry entry = GetDebugEntry(td);
                HandleDebugDuplicates(javaDuplicates, entry, td, cache);
                if (entry.JavaName.Length > module.JavaNameWidth)
                {
                    module.JavaNameWidth = (uint)entry.JavaName.Length + 1;
                }

                if (entry.ManagedName.Length > module.ManagedNameWidth)
                {
                    module.ManagedNameWidth = (uint)entry.ManagedName.Length + 1;
                }

                module.JavaToManagedMap.Add(entry);
                module.ManagedToJavaMap.Add(entry);
            }
            SyncDebugDuplicates(javaDuplicates);

            foreach (ModuleDebugData module in modules.Values)
            {
                PrepareDebugMaps(module);
            }

            string typeMapIndexPath = Path.Combine(outputDirectory, "typemap.index");

            using (var indexWriter = MemoryStreamPool.Shared.CreateBinaryWriter()) {
                OutputModules(modules, indexWriter, maxModuleFileNameWidth + 1);
                indexWriter.Flush();
                MonoAndroidHelper.CopyIfStreamChanged(indexWriter.BaseStream, typeMapIndexPath);
            }
            GeneratedBinaryTypeMaps.Add(typeMapIndexPath);

            GenerateNativeAssembly(
                (NativeAssemblerTargetProvider asmTargetProvider, bool sharedBitsWritten, bool sharedIncludeUsesAbiPrefix) => {
                return(new TypeMappingDebugNativeAssemblyGenerator(asmTargetProvider, new ModuleDebugData(), outputDirectory, sharedBitsWritten));
            }
                );

            return(true);
        }
Ejemplo n.º 23
0
		/// <summary>
		/// Sets the current type definition.
		/// </summary>
		public CppResolver WithCurrentTypeDefinition(ITypeDefinition typeDefinition)
		{
			if (this.CurrentTypeDefinition == typeDefinition)
				return this;
			
			TypeDefinitionCache newTypeDefinitionCache;
			if (typeDefinition != null)
				newTypeDefinitionCache = new TypeDefinitionCache(typeDefinition);
			else
				newTypeDefinitionCache = null;
			
			return new CppResolver(compilation, conversions, context.WithCurrentTypeDefinition(typeDefinition),
			                          checkForOverflow, isWithinLambdaExpression, newTypeDefinitionCache, localVariableStack, objectInitializerStack);
		}
Ejemplo n.º 24
0
        bool GenerateDebugNativeAssembly(bool skipJniAddNativeMethodRegistrationAttributeScan, List <TypeDefinition> javaTypes, TypeDefinitionCache cache, string outputDirectory, ApplicationConfigTaskState appConfState)
        {
            var javaToManaged = new List <TypeMapDebugEntry> ();
            var managedToJava = new List <TypeMapDebugEntry> ();

            var javaDuplicates = new Dictionary <string, List <TypeMapDebugEntry> > (StringComparer.Ordinal);

            foreach (TypeDefinition td in javaTypes)
            {
                UpdateApplicationConfig(td, appConfState);

                TypeMapDebugEntry entry = GetDebugEntry(td);
                HandleDebugDuplicates(javaDuplicates, entry, td, cache);

                javaToManaged.Add(entry);
                managedToJava.Add(entry);
            }
            SyncDebugDuplicates(javaDuplicates);

            var data = new ModuleDebugData {
                EntryCount       = (uint)javaToManaged.Count,
                JavaToManagedMap = javaToManaged,
                ManagedToJavaMap = managedToJava,
            };

            PrepareDebugMaps(data);
            GenerateNativeAssembly(
                (NativeAssemblerTargetProvider asmTargetProvider, bool sharedBitsWritten, bool sharedIncludeUsesAbiPrefix) => {
                return(new TypeMappingDebugNativeAssemblyGenerator(asmTargetProvider, data, outputDirectory, sharedBitsWritten, sharedIncludeUsesAbiPrefix));
            }
                );

            return(true);
        }
Ejemplo n.º 25
0
        void HandleDebugDuplicates(Dictionary <string, List <TypeMapDebugEntry> > javaDuplicates, TypeMapDebugEntry entry, TypeDefinition td, TypeDefinitionCache cache)
        {
            List <TypeMapDebugEntry> duplicates;

            if (!javaDuplicates.TryGetValue(entry.JavaName, out duplicates))
            {
                javaDuplicates.Add(entry.JavaName, new List <TypeMapDebugEntry> {
                    entry
                });
            }
            else
            {
                duplicates.Add(entry);
                TypeMapDebugEntry oldEntry = duplicates[0];
                if (td.IsAbstract || td.IsInterface || oldEntry.TypeDefinition.IsAbstract || oldEntry.TypeDefinition.IsInterface)
                {
                    if (td.IsAssignableFrom(oldEntry.TypeDefinition, cache))
                    {
                        oldEntry.TypeDefinition = td;
                        oldEntry.ManagedName    = GetManagedTypeName(td);
                    }
                }
            }
        }
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseCrc64;

            foreach (var dir in FrameworkDirectories)
            {
                if (Directory.Exists(dir.ItemSpec))
                {
                    res.SearchDirectories.Add(dir.ItemSpec);
                }
            }

            // Put every assembly we'll need in the resolver
            bool hasExportReference   = false;
            bool haveMonoAndroid      = false;
            var  allTypemapAssemblies = new HashSet <string> (StringComparer.OrdinalIgnoreCase);
            var  userAssemblies       = new Dictionary <string, string> (StringComparer.OrdinalIgnoreCase);

            foreach (var assembly in ResolvedAssemblies)
            {
                bool value;
                if (bool.TryParse(assembly.GetMetadata(AndroidSkipJavaStubGeneration), out value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {assembly.ItemSpec}");
                    continue;
                }

                bool   addAssembly = false;
                string fileName    = Path.GetFileName(assembly.ItemSpec);
                if (!hasExportReference && String.Compare("Mono.Android.Export.dll", fileName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    hasExportReference = true;
                    addAssembly        = true;
                }
                else if (!haveMonoAndroid && String.Compare("Mono.Android.dll", fileName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    haveMonoAndroid = true;
                    addAssembly     = true;
                }
                else if (MonoAndroidHelper.FrameworkAssembliesToTreatAsUserAssemblies.Contains(fileName))
                {
                    if (!bool.TryParse(assembly.GetMetadata(AndroidSkipJavaStubGeneration), out value) || !value)
                    {
                        string name = Path.GetFileNameWithoutExtension(fileName);
                        if (!userAssemblies.ContainsKey(name))
                        {
                            userAssemblies.Add(name, assembly.ItemSpec);
                        }
                        addAssembly = true;
                    }
                }

                if (addAssembly)
                {
                    allTypemapAssemblies.Add(assembly.ItemSpec);
                }

                res.Load(assembly.ItemSpec);
            }

            // However we only want to look for JLO types in user code for Java stub code generation
            foreach (var asm in ResolvedUserAssemblies)
            {
                if (bool.TryParse(asm.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {asm.ItemSpec}");
                    continue;
                }
                allTypemapAssemblies.Add(asm.ItemSpec);
                userAssemblies.Add(Path.GetFileNameWithoutExtension(asm.ItemSpec), asm.ItemSpec);
            }

            // Step 1 - Find all the JLO types
            var cache   = new TypeDefinitionCache();
            var scanner = new JavaTypeScanner(this.CreateTaskLogger(), cache)
            {
                ErrorOnCustomJavaObject = ErrorOnCustomJavaObject,
            };

            List <TypeDefinition> allJavaTypes = scanner.GetJavaTypes(allTypemapAssemblies, res);

            // Step 2 - Generate type maps
            //   Type mappings need to use all the assemblies, always.
            WriteTypeMappings(allJavaTypes, cache);

            var javaTypes = new List <TypeDefinition> ();

            foreach (TypeDefinition td in allJavaTypes)
            {
                if (!userAssemblies.ContainsKey(td.Module.Assembly.Name.Name) || JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(td, cache))
                {
                    continue;
                }

                javaTypes.Add(td);
            }

            // Step 3 - Generate Java stub code
            var success = CreateJavaSources(javaTypes, cache);

            if (!success)
            {
                return;
            }

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> (javaTypes.Count, StringComparer.Ordinal);
            var java    = new Dictionary <string, TypeDefinition> (javaTypes.Count, StringComparer.Ordinal);

            var managedConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);
            var javaConflicts    = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);

            using (var acw_map = MemoryStreamPool.Shared.CreateStreamWriter()) {
                foreach (TypeDefinition type in javaTypes)
                {
                    string managedKey = type.FullName.Replace('/', '.');
                    string javaKey    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                    acw_map.Write(type.GetPartialAssemblyQualifiedName(cache));
                    acw_map.Write(';');
                    acw_map.Write(javaKey);
                    acw_map.WriteLine();

                    TypeDefinition conflict;
                    bool           hasConflict = false;
                    if (managed.TryGetValue(managedKey, out conflict))
                    {
                        if (!managedConflicts.TryGetValue(managedKey, out var list))
                        {
                            managedConflicts.Add(managedKey, list = new List <string> {
                                conflict.GetPartialAssemblyName(cache)
                            });
                        }
                        list.Add(type.GetPartialAssemblyName(cache));
                        hasConflict = true;
                    }
                    if (java.TryGetValue(javaKey, out conflict))
                    {
                        if (!javaConflicts.TryGetValue(javaKey, out var list))
                        {
                            javaConflicts.Add(javaKey, list = new List <string> {
                                conflict.GetAssemblyQualifiedName(cache)
                            });
                        }
                        list.Add(type.GetAssemblyQualifiedName(cache));
                        success     = false;
                        hasConflict = true;
                    }
                    if (!hasConflict)
                    {
                        managed.Add(managedKey, type);
                        java.Add(javaKey, type);

                        acw_map.Write(managedKey);
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type, cache).Replace('/', '.'));
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();
                    }
                }

                acw_map.Flush();
                MonoAndroidHelper.CopyIfStreamChanged(acw_map.BaseStream, AcwMapFile);
            }

            foreach (var kvp in managedConflicts)
            {
                Log.LogCodedWarning("XA4214", Properties.Resources.XA4214, kvp.Key, string.Join(", ", kvp.Value));
                Log.LogCodedWarning("XA4214", Properties.Resources.XA4214_Result, kvp.Key, kvp.Value [0]);
            }

            foreach (var kvp in javaConflicts)
            {
                Log.LogCodedError("XA4215", Properties.Resources.XA4215, kvp.Key);
                foreach (var typeName in kvp.Value)
                {
                    Log.LogCodedError("XA4215", Properties.Resources.XA4215_Details, kvp.Key, typeName);
                }
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Placeholders    = ManifestPlaceholders;
            manifest.Assemblies.AddRange(userAssemblies.Values);
            manifest.Resolver          = res;
            manifest.SdkDir            = AndroidSdkDir;
            manifest.SdkVersion        = AndroidSdkPlatform;
            manifest.Debug             = Debug;
            manifest.MultiDex          = MultiDex;
            manifest.NeedsInternet     = NeedsInternet;
            manifest.InstantRunEnabled = InstantRunEnabled;

            var additionalProviders = manifest.Merge(Log, cache, allJavaTypes, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            // Only write the new manifest if it actually changed
            if (manifest.SaveIfChanged(Log, MergedAndroidManifestOutput))
            {
                Log.LogDebugMessage($"Saving: {MergedAndroidManifestOutput}");
            }

            // Create additional runtime provider java sources.
            string providerTemplateFile = "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = GetResource(providerTemplateFile);

            foreach (var provider in additionalProviders)
            {
                var contents      = providerTemplate.Replace("MonoRuntimeProvider", provider);
                var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java");
                MonoAndroidHelper.CopyIfStringChanged(contents, real_provider);
            }

            // Create additional application java sources.
            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in javaTypes)
            {
                if (JavaNativeTypeManager.IsApplication(type, cache) || JavaNativeTypeManager.IsInstrumentation(type, cache))
                {
                    string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(cache), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.Combine(OutputDirectory, "src", "mono", "android", "app");
            string applicationTemplateFile = "ApplicationRegistration.java";

            SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                         template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));
        }