static JavaTypeReference JavaTypeNameToReference(this JavaApi api, JavaTypeName tn, params JavaTypeParameters?[] contextTypeParameters) { var tp = contextTypeParameters.Where(tps => tps != null) .SelectMany(tps => tps !.TypeParameters) .FirstOrDefault(xp => xp.Name == tn.DottedName); if (tp != null) { return(new JavaTypeReference(tp, tn.ArrayPart)); } if (tn.DottedName == JavaTypeReference.GenericWildcard.SpecialName) { return(new JavaTypeReference(tn.BoundsType, tn.GenericConstraints?.Select(gc => JavaTypeNameToReference(api, gc, contextTypeParameters)), tn.ArrayPart)); } var primitive = JavaTypeReference.GetSpecialType(tn.DottedName); if (primitive != null) { return(tn.ArrayPart == null && tn.GenericConstraints == null ? primitive : new JavaTypeReference(primitive, tn.ArrayPart, tn.BoundsType, tn.GenericConstraints?.Select(gc => JavaTypeNameToReference(api, gc, contextTypeParameters)))); } var type = api.FindNonGenericType(tn.FullNameNonGeneric); return(new JavaTypeReference(type, tn.GenericArguments != null ? tn.GenericArguments.Select(_ => api.JavaTypeNameToReference(_, contextTypeParameters)).ToArray() : null, tn.ArrayPart)); }
public static void MarkOverrides(this JavaApi api, HashSet <JavaClass> doneList) { foreach (var kls in api.Packages.SelectMany(p => p.Types).OfType <JavaClass> ()) { kls.MarkOverrides(doneList); } }
public static void FindDefects(this JavaApi api) { foreach (var type in api.Packages.SelectMany(p => p.Types).Where(t => !t.IsReferenceOnly)) { type.FindDefects(); } }
public static JavaType FindNonGenericType(this JavaApi api, string?name) { var ret = FindPackages(api, name ?? "") .SelectMany(p => p.Types) .FirstOrDefault(t => name == (t.Parent?.Name != null ? t.Parent.Name + "." : "") + t.Name); if (ret == null) { ret = ManagedType.DummyManagedPackages .SelectMany(p => p.Types) .FirstOrDefault(t => t.FullName == name); } if (ret == null) { // We moved this type to "mono.android.app.IntentService" which makes this // type resolution fail if a user tries to reference it in Java. if (name == "android.app.IntentService") { return(FindNonGenericType(api, "mono.android.app.IntentService")); } throw new JavaTypeResolutionException(string.Format("Type '{0}' was not found.", name)); } return(ret); }
public static void LoadReferences(this JavaApi api, GenBase [] gens) { JavaPackage pkg = null; foreach (var gen in gens.Where(_ => _.IsAcw)) { pkg = api.Packages.FirstOrDefault(_ => _.Name == gen.PackageName); if (pkg == null) { pkg = new JavaPackage(api) { Name = gen.PackageName }; api.Packages.Add(pkg); } if (gen is InterfaceGen) { var iface = new JavaInterface(pkg); pkg.Types.Add(iface); iface.Load(gen); } else if (gen is ClassGen) { var kls = new JavaClass(pkg); pkg.Types.Add(kls); kls.Load(gen); } else { throw new InvalidOperationException(); } } }
public static void WriteParameterNamesXml(this JavaApi api, string file) { using (var xw = XmlWriter.Create(file, new XmlWriterSettings { Indent = true })) WriteParameterNamesXml(api, xw); }
public void Process(string inputXmlFile, GenBase [] gens, string outputXmlFile, int reportVerbosity) { switch (reportVerbosity) { case 0: break; case 1: Log.Verbosity = Log.LoggingLevel.Error; break; case 2: Log.Verbosity = Log.LoggingLevel.Warning; break; default: Log.Verbosity = Log.LoggingLevel.Debug; break; } var api = new JavaApi(); api.LoadReferences(gens); api.Load(inputXmlFile); api.StripNonBindables(); api.Resolve(); api.CreateGenericInheritanceMapping(); api.MarkOverrides(); api.FindDefects(); api.Save(outputXmlFile); }
public static void CreateGenericInheritanceMapping(this JavaApi api) { foreach (var kls in api.Packages.SelectMany(p => p.Types).OfType <JavaClass> ()) { kls.PrepareGenericInheritanceMapping(); } }
public static void Resolve(this JavaApi api) { while (true) { bool errors = false; foreach (var t in api.AllPackages.SelectMany(p => p.AllTypes).OfType <JavaClass> ().ToArray()) { try { t.Resolve(); } catch (JavaTypeResolutionException ex) { Log.LogError("Error while processing type '{0}': {1}", t, ex.Message); errors = true; t.Parent?.RemoveType(t); } } foreach (var t in api.AllPackages.SelectMany(p => p.AllTypes).OfType <JavaInterface> ().ToArray()) { try { t.Resolve(); } catch (JavaTypeResolutionException ex) { Log.LogError("Error while processing type '{0}': {1}", t, ex.Message); errors = true; t.Parent?.RemoveType(t); } } if (!errors) { break; } } }
public static void Save(this JavaApi api, XmlWriter writer) { writer.WriteStartElement("api"); foreach (var pkg in api.Packages) { if (!pkg.Types.Any(t => !t.IsReferenceOnly)) { continue; } writer.WriteStartElement("package"); writer.WriteAttributeString("name", pkg.Name); foreach (var type in pkg.Types) { if (type.IsReferenceOnly) { continue; // skip reference only types } if (type is JavaClass) { ((JavaClass)type).Save(writer); } else { ((JavaInterface)type).Save(writer); } } writer.WriteFullEndElement(); } writer.WriteFullEndElement(); }
public static void Save(this JavaApi api, string xmlfile) { using (var writer = XmlWriter.Create(xmlfile, new XmlWriterSettings() { Encoding = new UTF8Encoding(false, true), Indent = true, OmitXmlDeclaration = true, })) api.Save(writer); }
public void Process(string inputXmlFile, GenBase [] gens, string outputXmlFile) { var api = new JavaApi(); api.LoadReferences(gens); api.Load(inputXmlFile); api.Resolve(); api.CreateGenericInheritanceMapping(); api.MarkOverrides(); api.FindDefects(); api.Save(outputXmlFile); }
public static JavaType FindNonGenericType(this JavaApi api, string name) { var ret = api.Packages .SelectMany(p => p.Types) .FirstOrDefault(t => name.StartsWith(t.Parent.Name, StringComparison.Ordinal) && name == t.Parent.Name + '.' + t.Name); if (ret == null) { throw new JavaTypeResolutionException(string.Format("Type '{0}' was not found.", name)); } return(ret); }
static void Resolve(this JavaTypeParameters tp, JavaApi api, params JavaTypeParameters [] additionalTypeParameters) { foreach (var t in tp.TypeParameters) { if (t.GenericConstraints != null) { foreach (var g in t.GenericConstraints.GenericConstraints) { try { g.ResolvedType = api.Parse(g.Type, additionalTypeParameters); } catch (JavaTypeResolutionException ex) { Log.LogWarning("Warning: failed to resolve generic constraint: '{0}': {1}", g.Type, ex.Message); } } } } }
public static void Main(string [] args) { var inputXmlFile = args [0]; var outputXmlFile = args [1]; var api = new JavaApi(); api.Load(inputXmlFile); api.Resolve(); api.CreateGenericInheritanceMapping(); api.MarkOverrides(); api.FindDefects(); api.Save(outputXmlFile); }
public static void StripNonBindables(this JavaApi api) { var invalids = new List <JavaMember> (); foreach (var member in api.AllPackages.SelectMany(p => p.AllTypes) .SelectMany(t => t.Members).Where(m => m.Name != null && m.Name.Contains('$'))) { invalids.Add(member); } foreach (var invalid in invalids) { invalid.Parent?.Members.Remove(invalid); } }
static IEnumerable <JavaPackage> FindPackages(JavaApi api, string name) { // Given a type name like "java.lang.Object", return packages that could // possibly contain the type so we don't search all packages, ie: // - java.lang // - java var package_names = new List <string> (); int index; while ((index = name.LastIndexOf('.')) >= 0) { name = name.Substring(0, index); package_names.Add(name); } return(api.Packages.Where(p => package_names.Contains(p.Name, StringComparer.Ordinal)).ToList()); }
public static JavaType FindNonGenericType(this JavaApi api, string?name) { // Given a type name like 'android.graphics.BitmapFactory.Options' // We're going to search for: // - Pkg: android.graphics.BitmapFactory Type: Options // - Pkg: android.graphics Type: BitmapFactory.Options // - Pkg: android Type: graphics.BitmapFactory.Options // etc. We will short-circuit as soon as we find a match var index = name?.LastIndexOf('.') ?? -1; while (index > 0) { var ns = name !.Substring(0, index); var type_name = name.Substring(index + 1); if (api.Packages.TryGetValue(ns, out var pkg)) { if (pkg.Types.TryGetValue(type_name, out var type)) { return(type.First()); } } index = name.LastIndexOf('.', index - 1); } // See if it's purely a C# type var ret = ManagedType.DummyManagedPackages .SelectMany(p => p.AllTypes) .FirstOrDefault(t => t.FullName == name); if (ret == null) { // We moved this type to "mono.android.app.IntentService" which makes this // type resolution fail if a user tries to reference it in Java. if (name == "android.app.IntentService") { return(FindNonGenericType(api, "mono.android.app.IntentService")); } throw new JavaTypeResolutionException(string.Format("Type '{0}' was not found.", name)); } return(ret); }
public static JavaType FindNonGenericType(this JavaApi api, string name) { var ret = FindPackages(api, name) .SelectMany(p => p.Types) .FirstOrDefault(t => name == t.Parent.Name + '.' + t.Name); if (ret == null) { ret = ManagedType.DummyManagedPackages .SelectMany(p => p.Types) .FirstOrDefault(t => t.FullName == name); } if (ret == null) { throw new JavaTypeResolutionException(string.Format("Type '{0}' was not found.", name)); } return(ret); }
public static void Load(this JavaApi api, XmlReader reader, bool isReferenceOnly) { reader.MoveToContent(); if (reader.LocalName != "api") { throw XmlUtil.UnexpectedElementOrContent(null, reader, "api"); } api.ExtendedApiSource = reader.GetAttribute("api-source"); api.Platform = reader.GetAttribute("platform"); XmlUtil.CheckExtraneousAttributes("api", reader, "api-source", "platform"); if (reader.IsEmptyElement) { reader.Read(); } else { reader.Read(); do { reader.MoveToContent(); if (reader.NodeType == XmlNodeType.EndElement) { break; // </api> } if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "package") { throw XmlUtil.UnexpectedElementOrContent("api", reader, "package"); } var name = reader.GetAttribute("name"); if (!api.Packages.TryGetValue(name, out var pkg)) { pkg = new JavaPackage(api); api.Packages.Add(name, pkg); } pkg.Load(reader, isReferenceOnly); } while (true); XmlUtil.VerifyEndElement(reader, "api"); reader.Read(); } }
public static void Resolve(this JavaApi api) { while (true) { bool errors = false; foreach (var t in api.Packages.SelectMany(p => p.Types).OfType <JavaClass> ().ToArray()) { try { t.Resolve(); } catch (JavaTypeResolutionException ex) { Console.Error.WriteLine(string.Format("Error while processing type '{0}': {1}", t, ex.Message)); errors = true; t.Parent.Types.Remove(t); } } foreach (var t in api.Packages.SelectMany(p => p.Types).OfType <JavaInterface> ().ToArray()) { try { t.Resolve(); } catch (JavaTypeResolutionException ex) { Console.Error.WriteLine(string.Format("Error while processing type '{0}': {1}", t, ex.Message)); errors = true; t.Parent.Types.Remove(t); } } if (!errors) { break; } } }
static JavaTypeReference JavaTypeNameToReference(this JavaApi api, JavaTypeName tn, params JavaTypeParameters [] contextTypeParameters) { var tp = contextTypeParameters.Where(tps => tps != null).SelectMany(tps => tps.TypeParameters).FirstOrDefault(_ => _.Name == tn.FullNameNonGeneric); if (tp != null) { return(new JavaTypeReference(tp, tn.ArrayPart)); } var primitive = JavaTypeReference.GetSpecialType(tn.FullNameNonGeneric); if (primitive != null) { return(tn.ArrayPart == null ? primitive : new JavaTypeReference(primitive, tn.ArrayPart)); } var type = api.FindNonGenericType(tn.FullNameNonGeneric); return(new JavaTypeReference(type, tn.GenericArguments != null ? tn.GenericArguments.Select(_ => api.JavaTypeNameToReference(_, contextTypeParameters)).ToArray() : null, tn.ArrayPart)); }
public static void Save(this JavaApi api, XmlWriter writer) { writer.WriteStartElement("api"); if (api.Platform != null) { writer.WriteAttributeString("platform", api.Platform); } foreach (var pkg in api.AllPackages) { if (!pkg.AllTypes.Any(t => !t.IsReferenceOnly)) { continue; } writer.WriteStartElement("package"); writer.WriteAttributeString("name", pkg.Name); if (!string.IsNullOrEmpty(pkg.JniName)) { writer.WriteAttributeString("jni-name", pkg.JniName); } foreach (var type in pkg.AllTypes) { if (type.IsReferenceOnly) { continue; // skip reference only types } if (type is JavaClass) { ((JavaClass)type).Save(writer); } else { ((JavaInterface)type).Save(writer); } } writer.WriteFullEndElement(); } writer.WriteFullEndElement(); }
public static void WriteParameterNamesText(this JavaApi api, TextWriter writer) { Action <string, JavaTypeParameters> writeTypeParameters = (indent, tps) => { if (tps != null && tps.TypeParameters.Any()) { writer.Write($"{indent}<{string.Join (",", tps.TypeParameters.Select (p => p.Name))}>"); } }; foreach (var package in api.Packages) { writer.WriteLine(); writer.WriteLine($"package {package.Name}"); writer.WriteLine(";---------------------------------------"); foreach (var type in package.Types) { if (!type.Members.OfType <JavaMethodBase> ().Any(m => m.Parameters.Any())) { continue; // we care only about types that has any methods that have parameters. } writer.Write(type is JavaClass ? " class " : " interface "); writer.Write(type.Name); writeTypeParameters("", type.TypeParameters); writer.WriteLine(); // we care only about methods that have parameters. foreach (var mb in type.Members.OfType <JavaMethodBase> ().Where(m => m.Parameters.Any())) { writer.Write(" "); writeTypeParameters(" ", mb.TypeParameters); var name = mb is JavaConstructor ? "#ctor" : mb.Name; // For possible generic instances in parameter type, we replace all ", " with "," to ease parsing. writer.WriteLine($" {name}({string.Join (", ", mb.Parameters.Select (p => p.Type.Replace (", ", ",") + ' ' + p.Name))})"); } } } }
public static void LoadReferences(this JavaApi api, CodeGenerationOptions opt, IEnumerable <GenBase> gens) { JavaPackage pkg = null; foreach (var gen in gens.Where(_ => _.IsAcw)) { if (!api.Packages.TryGetValue(gen.PackageName, out pkg)) { pkg = new JavaPackage(api) { Name = gen.PackageName }; api.Packages.Add(pkg.Name, pkg); } if (gen is InterfaceGen iface_gen) { var iface = new JavaInterface(pkg); iface.Load(iface_gen); pkg.AddType(iface); } else if (gen is ClassGen class_gen) { var kls = new JavaClass(pkg); kls.Load(opt, class_gen); pkg.AddType(kls); } else { throw new InvalidOperationException(); } api.LoadReferences(opt, gen.NestedTypes); } }
public static void Load(this JavaApi api, string xmlfile) { using (var reader = XmlReader.Create(xmlfile)) api.Load(reader, false); }
/* * The Text Format is: * * package {packagename} * ;--------------------------------------- * interface {interfacename}{optional_type_parameters} -or- * class {classname}{optional_type_parameters} * {optional_type_parameters}{methodname}({parameters}) * * Anything after ; is treated as comment. * * optional_type_parameters: "" -or- "<A,B,C>" (no constraints allowed) * parameters: type1 p0, type2 p1 (pairs of {type} {name}, joined by ", ") * * It is with strict indentations. two spaces for types, four spaces for methods. * * Constructors are named as "#ctor". * * Commas are used by both parameter types and parameter separators, * but only parameter separators can be followed by a whitespace. * It is useful when writing text parsers for this format. * * Type names may contain whitespaces in case it is with generic constraints (e.g. "? extends FooBar"), * so when parsing a parameter type-name pair, the only trustworthy whitespace for tokenizing name is the *last* one. */ public static void WriteParameterNamesText(this JavaApi api, string file) { using (var sw = new StreamWriter(file)) WriteParameterNamesText(api, sw); }
public static void MarkOverrides(this JavaApi api) { api.MarkOverrides(new HashSet <JavaClass> ()); }
public JavaPackage(JavaApi parent) { Parent = parent; Types = new List <JavaType> (); }
public static void WriteParameterNamesXml(this JavaApi api, XmlWriter writer) { writer.WriteStartElement("parameter-names"); Action <JavaTypeParameters> writeTypeParameters = tps => { if (tps != null && tps.TypeParameters.Any()) { writer.WriteStartElement("type-parameters"); foreach (var gt in tps.TypeParameters) { writer.WriteStartElement("type-parameter"); writer.WriteAttributeString("name", gt.Name); // no need to supply constraints. writer.WriteEndElement(); } writer.WriteEndElement(); } }; foreach (var package in api.Packages) { writer.WriteStartElement("package"); writer.WriteAttributeString("name", package.Name); foreach (var type in package.Types) { if (!type.Members.OfType <JavaMethodBase> ().Any(m => m.Parameters.Any())) { continue; // we care only about types that has any methods that have parameters. } writer.WriteStartElement(type is JavaClass ? "class" : "interface"); writer.WriteAttributeString("name", type.Name); writeTypeParameters(type.TypeParameters); // we care only about methods that have parameters. foreach (var mb in type.Members.OfType <JavaMethodBase> ().Where(m => m.Parameters.Any())) { if (mb is JavaConstructor) { writer.WriteStartElement("constructor"); } else { writer.WriteStartElement("method"); writer.WriteAttributeString("name", mb.Name); } writeTypeParameters(mb.TypeParameters); foreach (var para in mb.Parameters) { writer.WriteStartElement("parameter"); // For possible generic instances in parameter type, we replace all ", " with "," to ease parsing. writer.WriteAttributeString("type", para.Type.Replace(", ", ",")); writer.WriteAttributeString("name", para.Name); writer.WriteEndElement(); } writer.WriteEndElement(); } writer.WriteEndElement(); } writer.WriteEndElement(); } writer.WriteEndElement(); }