public void GenericConstructors () { string xml = @"<api> <package name='XXX'> <class abstract='true' deprecated='not deprecated' final='false' name='GenericConstructors' static='false' visibility='public' jni-signature='Landroid/app/GenericConstructors'> <constructor deprecated='not deprecated' final='false' name='GenericConstructors' static='false' visibility='public' jni-signature='(LTTE;)V'> <typeParameters> <typeParameter name='E' interfaceBounds='' jni-interfaceBounds='' /> </typeParameters> <parameter name = 'e' type='E' jni-type='TE;'> </parameter> </constructor> </class> </package> </api>"; var xapi = new JavaApi (); using (var xr = XmlReader.Create (new StringReader (xml))) xapi.Load (xr, false); xapi.StripNonBindables (); xapi.Resolve (); xapi.CreateGenericInheritanceMapping (); xapi.MarkOverrides (); xapi.FindDefects (); var sw = new StringWriter (); using (var xw = XmlWriter.Create (sw)) xapi.Save (xw); xapi = new JavaApi (); using (var xr = XmlReader.Create (new StringReader (sw.ToString ()))) xapi.Load (xr, true); var t = xapi.Packages.First (_ => _.Name == "XXX").Types.First (_ => _.Name == "GenericConstructors"); var m = t.Members.OfType<JavaConstructor> ().FirstOrDefault (); Assert.IsNotNull (m.TypeParameters, "constructor not found"); }
public void SetupFixture() { api = JavaApiTestHelper.GetLoadedApi(); api.Resolve(); api.CreateGenericInheritanceMapping(); api.MarkOverrides(); }
public static JavaApi GetLoadedApi() { var api = new JavaApi(); using (var xr = XmlReader.Create(ApiPath)) api.Load(xr, false); return(api); }
public static JavaApi GetLoadedApi() { var api = new JavaApi(); using (var xr = XmlReader.Create(ApiPath, new XmlReaderSettings { XmlResolver = null })) api.Load(xr, false); return(api); }
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 void AdjustNotNullAnnotations() { var input = @" <api> <package name=""com.mypackage""> <class abstract=""false"" deprecated=""not deprecated"" jni-extends=""Ljava/lang/Object;"" extends=""java.lang.Object"" extends-generic-aware=""java.lang.Object"" final=""false"" name=""NotNullClass"" jni-signature=""Lcom/xamarin/NotNullClass;"" source-file-name=""NotNullClass.java"" static=""false"" visibility=""public""> <constructor deprecated=""not deprecated"" final=""false"" name=""NotNullClass"" static=""false"" visibility=""public"" bridge=""false"" synthetic=""false"" jni-signature=""()V"" /> <method abstract=""false"" deprecated=""not deprecated"" final=""false"" name=""notNullFunc"" native=""false"" return=""void"" jni-return=""V"" static=""false"" synchronized=""false"" visibility=""public"" bridge=""false"" synthetic=""false"" jni-signature=""(Ljava/lang/String;)V"" return-not-null=""true""> <parameter name=""value"" type=""java.lang.String"" jni-type=""Ljava/lang/String;"" not-null=""true"" /> </method> <field deprecated=""not deprecated"" final=""false"" name=""notNullField"" static=""false"" synthetic=""false"" transient=""false"" type=""java.lang.String"" type-generic-aware=""java.lang.String"" jni-signature=""Ljava/lang/String;"" not-null=""true"" visibility=""public"" volatile=""false"" /> </class> </package> </api>"; var api = new JavaApi(); api.LoadReferences(options, options.SymbolTable.AllRegisteredSymbols(options).OfType <GenBase> ().ToArray()); using (var sr = new StringReader(input)) using (var xml = XmlReader.Create(sr)) api.Load(xml, false); api.StripNonBindables(); api.Resolve(); api.CreateGenericInheritanceMapping(); api.MarkOverrides(); api.FindDefects(); using (var sb = new StringWriter()) { using (var writer = XmlWriter.Create(sb)) api.Save(writer); var root = XElement.Parse(sb.ToString()); Assert.AreEqual("true", root.Element("package").Element("class").Element("method").Attribute("return-not-null").Value); Assert.AreEqual("true", root.Element("package").Element("class").Element("method").Element("parameter").Attribute("not-null").Value); Assert.AreEqual("true", root.Element("package").Element("class").Element("field").Attribute("not-null").Value); } }
void FillSourceIdentifier(JavaApi api, string sourceIdentifier) { var ident = new SourceIdentifier(sourceIdentifier); Action <JavaMember> processMember = (member) => { var existing = member.GetExtension <SourceIdentifier> (); if (existing == null) { member.SetExtension(ident); } }; Action <JavaType> processType = (type) => { var existing = type.GetExtension <SourceIdentifier> (); if (existing == null) { type.SetExtension(ident); } foreach (var member in type.Members) { processMember(member); } }; Action <JavaPackage> processPackage = (pkg) => { var existing = pkg.GetExtension <SourceIdentifier> (); if (existing == null) { pkg.SetExtension(ident); } foreach (var type in pkg.Types) { processType(type); } }; foreach (var pkg in api.Packages) { processPackage(pkg); } }
public IEnumerable <ApiComparisonReport> Compare(JavaApi reference, JavaApi target) { var rtypes = reference.Packages.SelectMany(p => p.Types); foreach (var rtype in rtypes) { var ttype = target.Packages.FirstOrDefault(_ => _.Name == rtype.Parent.Name)?.Types?.FirstOrDefault(t => t.Name == rtype.Name); if (ttype == null) { yield return new ApiComparisonReport { Context = ttype, Issue = ApiComparisonIssue.MissingType, Message = $"Type `{rtype.FullName}` does not exist in the target API." } } ; else { foreach (var r in CompareType(rtype, ttype)) { yield return(r); } } } }
public void SetupFixture() { api = JavaApiTestHelper.GetLoadedApi(); }
/* * * The DroidDoc format from API Level 16 to 23, the format is: * * - All pages have ToC links and body (unlike standard JavaDoc which is based on HTML frames). * - The actual doc section is a div element whose id is "doc-col". * - The "doc-col" div element has a section div element whose id is "jd-header" and another one with id "jd-content". * - "jd-header" div element contains the type signature (modifiers, name, and inheritance). * - Here we care only about type name and kind (whether it is a class or interface). * - Generic arguments are insignificant. * - In the following terms I explain the "correct" (or "expected") document structure, but in fact * Google completely broke it and it is impossible to retrieve the document tree like this. * We workaround this issue by changing the strategy "iterate children of 'jd-content'" * with "iterate descendants of 'jd-content'"... It occurs only in API Level 15 or later. * - "jd-content" div element contains a collection of sections. Each section consists of: * - an "h2" element whose value text indicates the section name ("Public Constructors", "Protected Methods" etc.) * - There was an issue in javax/xml/validation/SchemaFactory.html in API Level 15 that the method details contain * "h2" and confuses the parser. To workaround this, we accept only limited kind of values. * - the content, which follows the h2 element. * - The section content is a collection of members. Each member consists of: * - an anchor ("A") element with "name" attribute, and * - a div element which contains an h4 child element whose class contains "jd-details-title". * - The h4 element contains the member signature. We parse it and retrieve the method name and list of parameters. * - Parameters are tokenized by ", ". * - Note that the splitter contains a white space which disambiguates any use of generic arguments (we don't want to split "Foo<K,V> bar" as "Foo<K" and "V> bar") * * API Level 10 to 15 has slightly different format: * * - There is no "doc-col" element. But "jd-header" and "jd-content" are still alive. * */ public void Import(ImporterOptions options) { options.DiagnosticWriter.WriteLine(options.DocumentDirectory); string referenceDocsTopDir = Path.Combine(options.DocumentDirectory, "reference"); var htmlFiles = Directory.GetDirectories(referenceDocsTopDir).SelectMany(d => Directory.GetFiles(d, "*.html", SearchOption.AllDirectories)); var api = new JavaApi(); foreach (var htmlFile in htmlFiles) { // skip irrelevant files. if (excludes.Any(x => htmlFile.EndsWith(x, StringComparison.OrdinalIgnoreCase))) { continue; } var packageName = Path.GetDirectoryName(htmlFile).Substring(referenceDocsTopDir.Length + 1).Replace('/', '.'); if (options.FrameworkOnly && non_frameworks.Any(n => packageName.StartsWith(n, StringComparison.Ordinal))) { continue; } options.DiagnosticWriter.WriteLine("-- " + htmlFile); var doc = new HtmlLoader().GetJavaDocFile(htmlFile); var header = doc.Descendants().FirstOrDefault(e => e.Attribute("id")?.Value == "jd-header"); var content = doc.Descendants().FirstOrDefault(e => e.Attribute("id")?.Value == "jd-content"); if (header == null || content == null) { continue; } var apiSignatureTokens = header.Value.Replace('\r', ' ').Replace('\n', ' ').Replace('\t', ' ').Trim(); if (apiSignatureTokens.Contains("extends ")) { apiSignatureTokens = apiSignatureTokens.Substring(0, apiSignatureTokens.IndexOf("extends ", StringComparison.Ordinal)).Trim(); } if (apiSignatureTokens.Contains("implements ")) { apiSignatureTokens = apiSignatureTokens.Substring(0, apiSignatureTokens.IndexOf("implements ", StringComparison.Ordinal)).Trim(); } bool isClass = apiSignatureTokens.Contains("class"); options.DiagnosticWriter.WriteLine(apiSignatureTokens); var javaPackage = api.Packages.FirstOrDefault(p => p.Name == packageName); if (javaPackage == null) { javaPackage = new JavaPackage(api) { Name = packageName }; api.Packages.Add(javaPackage); } var javaType = isClass ? (JavaType) new JavaClass(javaPackage) : new JavaInterface(javaPackage); javaType.Name = apiSignatureTokens.Substring(apiSignatureTokens.LastIndexOf(' ') + 1); javaPackage.Types.Add(javaType); string sectionType = null; var sep = new string [] { ", " }; var ssep = new char [] { ' ' }; foreach (var child in content.Descendants()) { if (child.Name == "h2") { var value = child.Value; switch (value) { case "Public Constructors": case "Protected Constructors": case "Public Methods": case "Protected Methods": sectionType = value; break; } continue; } if (sectionType == null) { continue; } if (child.Name != "a" || child.Attribute("name") == null) { continue; } var h4 = child.XPathSelectElement("following-sibling::div/h4[contains(@class, 'jd-details-title')]"); if (h4 == null) { continue; } string sigTypeOnly = child.Attribute("name").Value; string sigTypeAndName = h4.Value.Replace('\n', ' ').Replace('\r', ' ').Trim(); if (!sigTypeAndName.Contains('(')) { continue; } JavaMethodBase javaMethod = null; string name = sigTypeAndName.Substring(0, sigTypeAndName.IndexOf('(')).Split(ssep, StringSplitOptions.RemoveEmptyEntries).Last(); switch (sectionType) { case "Public Constructors": case "Protected Constructors": javaMethod = new JavaConstructor(javaType) { Name = name }; break; case "Public Methods": case "Protected Methods": string mname = sigTypeAndName.Substring(0, sigTypeAndName.IndexOf('(')); javaMethod = new JavaMethod(javaType) { Name = name }; break; } javaType.Members.Add(javaMethod); var paramTypes = SplitTypes(sigTypeOnly.Substring(sigTypeOnly.IndexOf('(') + 1).TrimEnd(')'), 0).ToArray(); var parameters = sigTypeAndName.Substring(sigTypeAndName.IndexOf('(') + 1).TrimEnd(')') .Split(sep, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim()) .ToArray(); foreach (var p in paramTypes.Zip(parameters, (to, tn) => new { Type = to, TypeAndName = tn }) .Select(pp => new { Type = pp.Type, Name = pp.TypeAndName.Split(' ') [1] })) { javaMethod.Parameters.Add(new JavaParameter(javaMethod) { Name = p.Name, Type = p.Type }); } } javaType.Members = javaType.Members.OfType <JavaMethodBase> () .OrderBy(m => m.Name + "(" + string.Join(",", m.Parameters.Select(p => p.Type)) + ")") .ToArray(); } foreach (var pkg in api.Packages) { pkg.Types = pkg.Types.OrderBy(t => t.Name).ToArray(); } api.Packages = api.Packages.OrderBy(p => p.Name).ToArray(); if (options.OutputTextFile != null) { api.WriteParameterNamesText(options.OutputTextFile); } if (options.OutputXmlFile != null) { api.WriteParameterNamesXml(options.OutputXmlFile); } }