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); }
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; }
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); }
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); } }
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); } }
public MonoDroidMarkStep(TypeDefinitionCache cache) { this.cache = cache; }
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; } } }
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; }
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); }
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); } }
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. }
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)); }
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); }
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); }
/// <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); }
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); }
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())); }