public void UnsignedMethodsXml() { // Ensure Kotlin unsigned types end up in the xml var klass = LoadClassFile("UnsignedTypes.class"); KotlinFixups.Fixup(new [] { klass }); var xml = new XmlClassDeclarationBuilder(klass).ToXElement(); Assert.AreEqual("uint", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_uint-WZ4Q5Ns").Attribute("return").Value); Assert.AreEqual("uint", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_uint-WZ4Q5Ns").Element("parameter").Attribute("type").Value); Assert.AreEqual("ushort", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ushort-xj2QHRw").Attribute("return").Value); Assert.AreEqual("ushort", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ushort-xj2QHRw").Element("parameter").Attribute("type").Value); Assert.AreEqual("ulong", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ulong-VKZWuLQ").Attribute("return").Value); Assert.AreEqual("ulong", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ulong-VKZWuLQ").Element("parameter").Attribute("type").Value); Assert.AreEqual("ubyte", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ubyte-7apg3OU").Attribute("return").Value); Assert.AreEqual("ubyte", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ubyte-7apg3OU").Element("parameter").Attribute("type").Value); Assert.AreEqual("uint[]", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_uintarray--ajY-9A").Attribute("return").Value); Assert.AreEqual("uint[]", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_uintarray--ajY-9A").Element("parameter").Attribute("type").Value); Assert.AreEqual("ushort[]", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ushortarray-rL5Bavg").Attribute("return").Value); Assert.AreEqual("ushort[]", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ushortarray-rL5Bavg").Element("parameter").Attribute("type").Value); Assert.AreEqual("ulong[]", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ulongarray-QwZRm1k").Attribute("return").Value); Assert.AreEqual("ulong[]", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ulongarray-QwZRm1k").Element("parameter").Attribute("type").Value); Assert.AreEqual("ubyte[]", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ubytearray-GBYM_sE").Attribute("return").Value); Assert.AreEqual("ubyte[]", xml.Elements("method").Single(f => f.Attribute("name").Value == "foo_ubytearray-GBYM_sE").Element("parameter").Attribute("type").Value); }
public void HandleKotlinNameShadowing() { var klass = LoadClassFile("NameShadowing.class"); KotlinFixups.Fixup(new [] { klass }); Assert.True(klass.Methods.Single(m => m.Name == "count").AccessFlags.HasFlag(MethodAccessFlags.Public)); Assert.True(klass.Methods.Single(m => m.Name == "hitCount").AccessFlags.HasFlag(MethodAccessFlags.Public)); Assert.True(klass.Methods.Single(m => m.Name == "setType").AccessFlags.HasFlag(MethodAccessFlags.Public)); }
public void HideInternalClass() { var klass = LoadClassFile("InternalClass.class"); Assert.True(klass.AccessFlags.HasFlag(ClassAccessFlags.Public)); KotlinFixups.Fixup(new [] { klass }); Assert.False(klass.AccessFlags.HasFlag(ClassAccessFlags.Public)); }
public void HideImplementationMethod() { var klass = LoadClassFile("MethodImplementation.class"); var method = klass.Methods.First(m => m.Name == "toString-impl"); Assert.True(method.AccessFlags.HasFlag(MethodAccessFlags.Public)); KotlinFixups.Fixup(new [] { klass }); Assert.False(method.AccessFlags.HasFlag(MethodAccessFlags.Public)); }
public void HideInternalConstructor() { var klass = LoadClassFile("InternalConstructor.class"); var ctor = klass.Methods.First(m => m.Name == "<init>"); Assert.True(ctor.AccessFlags.HasFlag(MethodAccessFlags.Public)); KotlinFixups.Fixup(new [] { klass }); Assert.False(ctor.AccessFlags.HasFlag(MethodAccessFlags.Public)); }
public void HideInternalMethod() { var klass = LoadClassFile("InternalMethod.class"); var method = klass.Methods.First(m => m.Name == "take$main"); Assert.True(method.AccessFlags.HasFlag(MethodAccessFlags.Public)); KotlinFixups.Fixup(new [] { klass }); Assert.False(method.AccessFlags.HasFlag(MethodAccessFlags.Public)); }
public void CreateMethod_EnsureKotlinHashcodeFix() { var xml = XDocument.Parse("<package name=\"com.example.test\" jni-name=\"com/example/test\"><class name=\"test\"><method name=\"add-h-_1V8i\" final=\"false\" /></class></package>"); var klass = XmlApiImporter.CreateClass(xml.Root, xml.Root.Element("class")); KotlinFixups.Fixup(new [] { (GenBase)klass }.ToList()); Assert.AreEqual("Add", klass.Methods [0].Name); Assert.IsTrue(klass.Methods [0].IsFinal); Assert.IsFalse(klass.Methods [0].IsVirtual); }
public void RenameSetterParameter() { var klass = LoadClassFile("SetterParameterName.class"); var setter = klass.Methods.First(m => m.Name == "setCity"); var p = setter.GetParameters() [0]; Assert.AreEqual("p0", p.Name); KotlinFixups.Fixup(new [] { klass }); Assert.AreEqual("value", p.Name); }
public void ParameterName() { var klass = LoadClassFile("ParameterName.class"); var method = klass.Methods.First(m => m.Name == "take"); var p = method.GetParameters() [0]; Assert.AreEqual("p0", p.Name); KotlinFixups.Fixup(new [] { klass }); Assert.AreEqual("count", p.Name); }
public void RenameExtensionParameter() { var klass = LoadClassFile("RenameExtensionParameterKt.class"); var method = klass.Methods.First(m => m.Name == "toUtf8String"); var p = method.GetParameters() [0]; Assert.AreEqual("$this$toUtf8String", p.Name); KotlinFixups.Fixup(new [] { klass }); Assert.AreEqual("obj", p.Name); }
public void HideInternalProperty() { var klass = LoadClassFile("InternalProperty.class"); var getter = klass.Methods.First(m => m.Name == "getCity$main"); var setter = klass.Methods.First(m => m.Name == "setCity$main"); Assert.True(getter.AccessFlags.HasFlag(MethodAccessFlags.Public)); Assert.True(setter.AccessFlags.HasFlag(MethodAccessFlags.Public)); KotlinFixups.Fixup(new [] { klass }); Assert.False(getter.AccessFlags.HasFlag(MethodAccessFlags.Public)); Assert.False(setter.AccessFlags.HasFlag(MethodAccessFlags.Public)); }
public void UnsignedFieldsXml() { // Ensure Kotlin unsigned types end up in the xml var klass = LoadClassFile("UnsignedTypesKt.class"); KotlinFixups.Fixup(new [] { klass }); var xml = new XmlClassDeclarationBuilder(klass).ToXElement(); Assert.AreEqual("uint", xml.Elements("field").Single(f => f.Attribute("name").Value == "UINT_CONST").Attribute("type").Value); Assert.AreEqual("ushort", xml.Elements("field").Single(f => f.Attribute("name").Value == "USHORT_CONST").Attribute("type").Value); Assert.AreEqual("ulong", xml.Elements("field").Single(f => f.Attribute("name").Value == "ULONG_CONST").Attribute("type").Value); Assert.AreEqual("ubyte", xml.Elements("field").Single(f => f.Attribute("name").Value == "UBYTE_CONST").Attribute("type").Value); }
public void HideInternalConstructor() { var klass = LoadClassFile("InternalConstructor.class"); var ctor = klass.Methods.First(m => m.Name == "<init>"); Assert.True(ctor.AccessFlags.HasFlag(MethodAccessFlags.Public)); KotlinFixups.Fixup(new [] { klass }); Assert.False(ctor.AccessFlags.HasFlag(MethodAccessFlags.Public)); var output = new XmlClassDeclarationBuilder(klass).ToXElement().ToString(); Assert.True(output.Contains("visibility=\"kotlin-internal\"")); }
public void UnsignedFields() { var klass = LoadClassFile("UnsignedTypesKt.class"); var uint_field = klass.Fields.Single(m => m.Name == "UINT_CONST"); var ushort_field = klass.Fields.Single(m => m.Name == "USHORT_CONST"); var ulong_field = klass.Fields.Single(m => m.Name == "ULONG_CONST"); var ubyte_field = klass.Fields.Single(m => m.Name == "UBYTE_CONST"); KotlinFixups.Fixup(new [] { klass }); Assert.AreEqual("uint", uint_field.KotlinType); Assert.AreEqual("ushort", ushort_field.KotlinType); Assert.AreEqual("ulong", ulong_field.KotlinType); Assert.AreEqual("ubyte", ubyte_field.KotlinType); }
public void UnsignedMethods() { var klass = LoadClassFile("UnsignedTypes.class"); var uint_method = klass.Methods.Single(m => m.Name.Contains("foo_uint-")); var ushort_method = klass.Methods.Single(m => m.Name.Contains("foo_ushort-")); var ulong_method = klass.Methods.Single(m => m.Name.Contains("foo_ulong-")); var ubyte_method = klass.Methods.Single(m => m.Name.Contains("foo_ubyte-")); var uintarray_method = klass.Methods.Single(m => m.Name.Contains("foo_uintarray-")); var ushortarray_method = klass.Methods.Single(m => m.Name.Contains("foo_ushortarray-")); var ulongarray_method = klass.Methods.Single(m => m.Name.Contains("foo_ulongarray-")); var ubytearray_method = klass.Methods.Single(m => m.Name.Contains("foo_ubytearray-")); var uintarrayarray_method = klass.Methods.Single(m => m.Name.Contains("foo_uintarrayarray")); KotlinFixups.Fixup(new [] { klass }); Assert.AreEqual("uint", uint_method.GetParameters() [0].KotlinType); Assert.AreEqual("uint", uint_method.KotlinReturnType); Assert.AreEqual("ushort", ushort_method.GetParameters() [0].KotlinType); Assert.AreEqual("ushort", ushort_method.KotlinReturnType); Assert.AreEqual("ulong", ulong_method.GetParameters() [0].KotlinType); Assert.AreEqual("ulong", ulong_method.KotlinReturnType); Assert.AreEqual("ubyte", ubyte_method.GetParameters() [0].KotlinType); Assert.AreEqual("ubyte", ubyte_method.KotlinReturnType); Assert.AreEqual("uint[]", uintarray_method.GetParameters() [0].KotlinType); Assert.AreEqual("uint[]", uintarray_method.KotlinReturnType); Assert.AreEqual("ushort[]", ushortarray_method.GetParameters() [0].KotlinType); Assert.AreEqual("ushort[]", ushortarray_method.KotlinReturnType); Assert.AreEqual("ulong[]", ulongarray_method.GetParameters() [0].KotlinType); Assert.AreEqual("ulong[]", ulongarray_method.KotlinReturnType); Assert.AreEqual("ubyte[]", ubytearray_method.GetParameters() [0].KotlinType); Assert.AreEqual("ubyte[]", ubytearray_method.KotlinReturnType); // Kotlin's Array<UIntArray> does not trigger this code because it is not // encoded as Java's "[[I", instead it is exposed as "UIntArray[]", so // we treat it as a normal class array. Assert.Null(uintarrayarray_method.GetParameters() [0].KotlinType); Assert.Null(uintarrayarray_method.KotlinReturnType); }
public void HideInternalClass() { var klass = LoadClassFile("InternalClass.class"); var inner_class = klass.InnerClasses.First(); Assert.True(klass.AccessFlags.HasFlag(ClassAccessFlags.Public)); Assert.True(inner_class.InnerClassAccessFlags.HasFlag(ClassAccessFlags.Public)); KotlinFixups.Fixup(new [] { klass }); Assert.False(klass.AccessFlags.HasFlag(ClassAccessFlags.Public)); Assert.False(inner_class.InnerClassAccessFlags.HasFlag(ClassAccessFlags.Public)); var output = new XmlClassDeclarationBuilder(klass).ToXElement().ToString(); Assert.True(output.Contains("visibility=\"private\"")); }
public void HideInternalProperty() { var klass = LoadClassFile("InternalProperty.class"); var getter = klass.Methods.First(m => m.Name == "getCity$main"); var setter = klass.Methods.First(m => m.Name == "setCity$main"); Assert.True(getter.AccessFlags.HasFlag(MethodAccessFlags.Public)); Assert.True(setter.AccessFlags.HasFlag(MethodAccessFlags.Public)); KotlinFixups.Fixup(new [] { klass }); Assert.False(getter.AccessFlags.HasFlag(MethodAccessFlags.Public)); Assert.False(setter.AccessFlags.HasFlag(MethodAccessFlags.Public)); var output = new XmlClassDeclarationBuilder(klass).ToXElement().ToString(); Assert.True(output.Contains("visibility=\"kotlin-internal\"")); }
public void MakeInternalInterfacePackagePrivate() { var klass = LoadClassFile("InternalInterface.class"); var inner_class = klass.InnerClasses.First(); Assert.True(klass.AccessFlags.HasFlag(ClassAccessFlags.Public)); Assert.True(inner_class.InnerClassAccessFlags.HasFlag(ClassAccessFlags.Public)); KotlinFixups.Fixup(new [] { klass }); // "package-private" is denoted as no visibility flags Assert.False(klass.AccessFlags.HasFlag(ClassAccessFlags.Public)); Assert.False(klass.AccessFlags.HasFlag(ClassAccessFlags.Protected)); Assert.False(klass.AccessFlags.HasFlag(ClassAccessFlags.Private)); Assert.False(inner_class.InnerClassAccessFlags.HasFlag(ClassAccessFlags.Public)); Assert.False(inner_class.InnerClassAccessFlags.HasFlag(ClassAccessFlags.Protected)); Assert.False(inner_class.InnerClassAccessFlags.HasFlag(ClassAccessFlags.Private)); }
public void HideDefaultConstructorMarker() { var klass = LoadClassFile("DefaultConstructor.class"); // init () var ctor_0p = klass.Methods.Single(m => m.Name == "<init>" && m.GetParameters().Length == 0); // init (string name) var ctor_1p = klass.Methods.Single(m => m.Name == "<init>" && m.GetParameters().Length == 1); // init (string p0, int p1, DefaultConstructorMarker p2) var ctor_3p = klass.Methods.Single(m => m.Name == "<init>" && m.GetParameters().Length == 3); Assert.True(ctor_3p.AccessFlags.HasFlag(MethodAccessFlags.Public)); KotlinFixups.Fixup(new [] { klass }); // Assert that the normal constructors are still public Assert.True(ctor_0p.AccessFlags.HasFlag(MethodAccessFlags.Public)); Assert.True(ctor_1p.AccessFlags.HasFlag(MethodAccessFlags.Public)); // Assert that the synthetic "DefaultConstructorMarker" constructor has been marked private Assert.False(ctor_3p.AccessFlags.HasFlag(MethodAccessFlags.Public)); }
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); } 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.UseShortFileNames); gen_info.GenerateLibraryProjectFile(options, enumFiles); }