public void ExternalFlagsEnumerationTest() { // This should create a new enum with [Flags] because of the "enumFlags" parameter var csv = "10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; var mappings = new EnumMappings(string.Empty, string.Empty, "30", false); var sr = new StringReader(csv); var removes = new List <KeyValuePair <string, string> > (); var enums = mappings.ParseFieldMappings(sr, new [] { "Org.XmlPull.V1.XmlPullParserNode" }, 30, removes); Assert.AreEqual(true, enums.Single().Value.BitField); }
public void ApiVersionExcludedV2Test() { // This should be completely ignored because it's API=10 and we're looking for API=5 var csv = "E,10,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,Org.XmlPull.V1.XmlPullParserNode,Cdsect"; var mappings = new EnumMappings(string.Empty, string.Empty, "5", false); var sr = new StringReader(csv); var removes = new List <KeyValuePair <string, string> > (); var enums = mappings.ParseFieldMappings(sr, new string [0], 5, removes); Assert.AreEqual(0, removes.Count); Assert.AreEqual(0, enums.Count); }
public void RemoveFieldOnlyTest() { // This should only remove the field var csv = "10,,,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; var mappings = new EnumMappings(string.Empty, string.Empty, "30", false); var sr = new StringReader(csv); var removes = new List <KeyValuePair <string, string> > (); var enums = mappings.ParseFieldMappings(sr, new string [0], 30, removes); Assert.AreEqual("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single().ToString()); Assert.AreEqual(0, enums.Count); }
public void TransientRemoveFieldOnlyTest() { // Transient has no effect here var csv = $"- ENTER TRANSIENT MODE -{Environment.NewLine}10,,,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; var mappings = new EnumMappings(string.Empty, string.Empty, "30", false); var sr = new StringReader(csv); var removes = new List <KeyValuePair <string, string> > (); var enums = mappings.ParseFieldMappings(sr, new string [0], 30, removes); Assert.AreEqual("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single().ToString()); Assert.AreEqual(0, enums.Count); }
public void AddConstantOnlyTest() { // This should only add an enum var csv = "10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,,5"; var mappings = new EnumMappings(string.Empty, string.Empty, "30", false); var sr = new StringReader(csv); var removes = new List <KeyValuePair <string, string> > (); var enums = mappings.ParseFieldMappings(sr, new string [0], 30, removes); Assert.AreEqual(0, removes.Count); Assert.AreEqual("Org.XmlPull.V1.XmlPullParserNode", enums.Single().Key); Assert.AreEqual(false, enums.Single().Value.BitField); Assert.AreEqual(true, enums.Single().Value.FieldsRemoved); Assert.AreEqual("[Cdsect, ]", enums.First().Value.JniNames.Single().ToString()); Assert.AreEqual("[Cdsect, 5]", enums.First().Value.Members.Single().ToString()); }
public void TransientEnumificationV2Test() { // This should create a new enum and remove the field var csv = "E,10,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,Org.XmlPull.V1.XmlPullParserNode,Cdsect,remove"; var mappings = new EnumMappings(string.Empty, string.Empty, "30", false); var sr = new StringReader(csv); var removes = new List <KeyValuePair <string, string> > (); var enums = mappings.ParseFieldMappings(sr, new string [0], 30, removes); Assert.AreEqual("[I:org/xmlpull/v1/XmlPullParser.CDSECT, Org.XmlPull.V1.XmlPullParserNode]", removes.Single().ToString()); Assert.AreEqual("Org.XmlPull.V1.XmlPullParserNode", enums.Single().Key); Assert.AreEqual(false, enums.Single().Value.BitField); Assert.AreEqual(false, enums.Single().Value.FieldsRemoved); Assert.AreEqual("[Cdsect, I:org/xmlpull/v1/XmlPullParser.CDSECT]", enums.First().Value.JniNames.Single().ToString()); Assert.AreEqual("[Cdsect, 5]", enums.First().Value.Members.Single().ToString()); }
public void XmlEnumMapWithMixedJNI() { var xml = @"<enum-field-mappings> <mapping jni-class='android/support/v4/app/FragmentActivity$FragmentTag' clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'> <field clr-name='Name' value='0' /> <field jni-name='Fragment_id' clr-name='Id' value='1' /> <field clr-name='Tag' value='2' /> </mapping> </enum-field-mappings>" ; var doc = XDocument.Parse(xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); var sr = EnumMappings.FieldXmlToCsv(doc); var lines = sr.ReadToEnd().Split(new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); var expected = new [] { "0, Android.Support.V4.App.FragmentTagType, Name, , 0, Flags", "0, Android.Support.V4.App.FragmentTagType, Id, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_id, 1, Flags", "0, Android.Support.V4.App.FragmentTagType, Tag, , 2, Flags" }; Assert.AreEqual(expected, lines); }
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; string api_versions_xml = options.ApiVersionsXmlFile; 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 }; // Load reference libraries foreach (var lib in options.LibraryPaths) { resolver.SearchDirectories.Add(lib); } foreach (var reference in references) { resolver.SearchDirectories.Add(Path.GetDirectoryName(reference)); } foreach (var reference in references) { 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)) { 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. string apiXmlFile = filename; string apiSourceAttr = null; using (var xr = XmlReader.Create(filename)) { xr.MoveToContent(); apiSourceAttr = xr.GetAttribute("api-source"); } if (apiSourceAttr == "class-parse") { apiXmlFile = api_xml_adjuster_output ?? Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename) + ".adjusted"); new Adjuster().Process(filename, SymbolTable.AllRegisteredSymbols().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(); List <GenBase> gens = p.Parse(apiXmlFile, fixups, api_level, product_version); if (gens == null) { return; } apiSource = p.ApiSource; opt.Gens = gens; // 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(); if (gen.IsGeneratable) { AddTypeToTable(gen); } } Validate(gens, opt); if (api_versions_xml != null) { ApiVersionsSupport.AssignApiLevels(gens, api_versions_xml); } foreach (GenBase gen in gens) { gen.FillProperties(); } foreach (var gen in gens) { gen.UpdateEnums(opt); } foreach (GenBase gen in gens) { gen.FixupMethodOverrides(); } foreach (GenBase gen in gens) { gen.FixupExplicitImplementation(); } 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); }
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() { ApiXmlFile = options.ApiDescriptionFile, 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, new XmlReaderSettings { XmlResolver = null })) { xr.MoveToContent(); apiSourceAttr = xr.GetAttribute("api-source"); } var is_classparse = apiSourceAttr == "class-parse"; // Resolve types using Java.Interop.Tools.JavaTypeSystem if (is_classparse && !options.UseLegacyJavaResolver) { var output_xml = api_xml_adjuster_output ?? Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename) + ".adjusted"); JavaTypeResolutionFixups.Fixup(filename, output_xml, resolver, references.Distinct().ToArray()); if (only_xml_adjuster) { return; } // Use this output for future steps filename = output_xml; apiXmlFile = filename; is_classparse = false; } // 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 = !is_classparse; 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.LogCodedWarning(0, Report.WarningAssemblyParseFailure, ex, reference, ex.Message); } } // For class-parse API description, transform it to jar2xml style. // Resolve types using ApiXmlAdjuster if (is_classparse && options.UseLegacyJavaResolver) { 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); } // Load the API XML document var api = ApiXmlDocument.Load(apiXmlFile, api_level, product_version); if (api is null) { return; } // Apply metadata fixups foreach (var fixup in fixups) { api.ApplyFixupFile(fixup); } api.ApiDocument.Save(apiXmlFile + ".fixed"); // Parse API XML var gens = XmlApiImporter.Parse(api.ApiDocument, opt); if (gens is null) { return; } apiSource = api.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); JavadocFixups.Fixup(gens, options); //SymbolTable.Dump (); GenerationInfo gen_info = new GenerationInfo(csdir, javadir, assemblyQN); opt.AssemblyName = gen_info.Assembly; if (mapping_file != null) { GenerateMappingReportFile(gens, mapping_file); } foreach (IGeneratable gen in gens) { if (gen.IsGeneratable) { gen.Generate(opt, gen_info); } } new NamespaceMapping(gens).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); gen_info.GenerateLibraryProjectFile(options, enumFiles); }