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);
        }
Example #5
0
        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);
        }
Example #6
0
        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);
            }
        }
Example #7
0
        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);
            }
        }
Example #8
0
        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);
                    }
                }
            }
        }
Example #9
0
 public void SetupFixture()
 {
     api = JavaApiTestHelper.GetLoadedApi();
 }
Example #10
0
        /*
         *
         * 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);
            }
        }