Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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());
        }
Beispiel #6
0
        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());
        }
Beispiel #7
0
        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);
        }
Beispiel #8
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;
            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);
        }
Beispiel #9
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()
            {
                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);
        }