From 086ededbd3194f3d43feaa90d82a5a60555a3052 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 6 Sep 2017 18:47:46 +0200 Subject: [PATCH] [api-merge] add deprecation platform information to API description While the merged API description file contains information about deprecation status of a given API, it lacks information on when the API (which Android platform) was deprecated. This information will be needed for new Java code generator (currently WIP). To make gathering the information easier, each platform .xml.in file gains a `platform` attribute in its `api` root element. --- build-tools/api-merge/ApiDescription.cs | 105 ++++++++++++++++++++---- src/Mono.Android/Profiles/api-10.xml.in | 2 +- src/Mono.Android/Profiles/api-15.xml.in | 2 +- src/Mono.Android/Profiles/api-16.xml.in | 2 +- src/Mono.Android/Profiles/api-17.xml.in | 2 +- src/Mono.Android/Profiles/api-18.xml.in | 2 +- src/Mono.Android/Profiles/api-19.xml.in | 2 +- src/Mono.Android/Profiles/api-20.xml.in | 2 +- src/Mono.Android/Profiles/api-21.xml.in | 2 +- src/Mono.Android/Profiles/api-22.xml.in | 2 +- src/Mono.Android/Profiles/api-23.xml.in | 2 +- src/Mono.Android/Profiles/api-24.xml.in | 2 +- src/Mono.Android/Profiles/api-25.xml.in | 2 +- src/Mono.Android/Profiles/api-26.xml.in | 2 +- 14 files changed, 102 insertions(+), 29 deletions(-) diff --git a/build-tools/api-merge/ApiDescription.cs b/build-tools/api-merge/ApiDescription.cs index fda99caf88b..85eaf4a2fa3 100644 --- a/build-tools/api-merge/ApiDescription.cs +++ b/build-tools/api-merge/ApiDescription.cs @@ -20,11 +20,29 @@ class ApiDescription { public ApiDescription (string source) { Contents = XDocument.Load (source); - foreach (var package in Contents.Element ("api").Elements ("package")) { - AddPackage (package); + + string platform; + XElement api = GetRoot (Contents, source, out platform); + foreach (var package in api.Elements ("package")) { + AddPackage (package, platform); } } + XElement GetRoot (XDocument doc, string sourcePath, out string platform) + { + XElement api = doc.Element ("api"); + XAttribute platformAttribute = api.Attributes ("platform").LastOrDefault (); + if (platformAttribute != null) + platform = platformAttribute.Value?.Trim (); + else + platform = null; + + if (String.IsNullOrEmpty (platform)) + throw new InvalidOperationException ($"API source '{sourcePath}' root element misses the 'platform' attribute"); + + return api; + } + public void Merge (string apiLocation) { #if ADD_OBSOLETE_ON_DISAPPEARANCE @@ -32,18 +50,22 @@ public void Merge (string apiLocation) int apiLevel = int.Parse (filename.Substring (4, filename.IndexOf ('.', 4) - 4)); #endif var n = XDocument.Load (apiLocation); - foreach (var npackage in n.Elements ("api").Elements ("package")) { + string platform = null; + XElement api = GetRoot (n, apiLocation, out platform); + + foreach (var npackage in api.Elements ("package")) { var spackage = GetPackage ((string) npackage.Attribute ("name")); if (spackage == null) { - AddNewPackage (npackage, apiLocation); + AddNewPackage (npackage, apiLocation, platform); continue; } foreach (var ntype in npackage.Elements ()) { var stype = GetType (spackage, ntype); if (stype == null) { - AddNewType (spackage, ntype, apiLocation); + AddNewType (spackage, ntype, apiLocation, platform); continue; } + UpdateDeprecatedSince (stype, ntype, platform); foreach (var a in ntype.Attributes ()) { var sattr = stype.Attribute (a.Name); switch (a.Name.LocalName) { @@ -89,9 +111,11 @@ public void Merge (string apiLocation) foreach (var nmember in ntype.Elements ()) { var smember = GetMember (stype, nmember); if (smember == null) { - AddNewMember (stype, nmember, apiLocation); + AddNewMember (stype, nmember, apiLocation, platform); continue; } + + UpdateDeprecatedSince (smember, nmember, platform); if (nmember.Name.LocalName == "field") { // FIXME: enable this to get the latest field attributes precisely. /* @@ -114,7 +138,7 @@ public void Merge (string apiLocation) if (nmember.Name.LocalName == "method" || nmember.Name.LocalName == "constructor") { smember = GetConstructorOrMethod (stype, nmember); if (smember == null) { - AddNewMember (stype, nmember, apiLocation); + AddNewMember (stype, nmember, apiLocation, platform); continue; } foreach (var a in nmember.Attributes ()) { @@ -177,7 +201,7 @@ public void Save (string filename) void FixupOverrides () { - foreach (var type in Contents.Elements ("api").Elements ("package").Elements ("class")) { + foreach (var type in Contents.Element ("api").Elements ("package").Elements ("class")) { foreach (var method in type.Elements ("method")) { XElement baseType, sourceType = type; string extends; @@ -193,14 +217,14 @@ void FixupOverrides () } } - void AddPackage (XElement package) + void AddPackage (XElement package, string platform) { foreach (var type in package.Elements ()) { - AddType (type); + AddType (type, platform); } } - void AddType (XElement type) + void AddType (XElement type, string platform) { string package = (string) type.Parent.Attribute ("name"); string typeName = (string) type.Attribute ("name"); @@ -215,9 +239,56 @@ void AddType (XElement type) } return; } + UpdateDeprecatedSince (type, platform); Types.Add (fullName, type); } + void UpdateDeprecatedSince (XElement oldElement, XElement newElement, string platform) + { + if (oldElement == null || newElement == null) + return; + + XAttribute deprecatedNew = newElement.Attributes ("deprecated").LastOrDefault (); + if (deprecatedNew == null) + // Removal of the attribute doesn't affect deprecated-since + return; + + XAttribute deprecatedOld = oldElement.Attributes ("deprecated").LastOrDefault (); + + bool deprecatedSinceNow = false; + if (deprecatedOld == null) { + deprecatedSinceNow |= String.Compare ("deprecated", deprecatedNew.Value, StringComparison.Ordinal) == 0; + } else if (String.Compare ("not deprecated", deprecatedOld.Value, StringComparison.Ordinal) == 0 && + String.Compare ("deprecated", deprecatedNew.Value, StringComparison.Ordinal) == 0) { + deprecatedSinceNow = true; + } + + if (!deprecatedSinceNow) + return; + + SetDeprecatedSince (oldElement, platform); + } + + void UpdateDeprecatedSince (XElement newElement, string platform) + { + XAttribute deprecated = newElement?.Attributes ("deprecated").LastOrDefault (); + if (deprecated == null || String.Compare ("deprecated", deprecated.Value, StringComparison.Ordinal) != 0) + return; + SetDeprecatedSince (newElement, platform); + } + + void SetDeprecatedSince (XElement element, string platform) + { + if (element == null) + return; + + XAttribute deprecatedSince = element.Attributes ("deprecated-since").LastOrDefault (); + if (deprecatedSince == null) + element.Add (new XAttribute ("deprecated-since", platform)); + else + deprecatedSince.SetValue (platform); + } + XElement AddWithLocation (XElement old, XElement child, string location) { child.Add (new XAttribute ("merge.SourceFile", location)); @@ -225,25 +296,27 @@ XElement AddWithLocation (XElement old, XElement child, string location) return (XElement) old.LastNode; } - void AddNewPackage (XElement newPackage, string location) + void AddNewPackage (XElement newPackage, string location, string platform) { + UpdateDeprecatedSince (newPackage, platform); AddWithLocation (Contents.Element ("api"), newPackage, location); } - void AddNewType (XElement sourcePackage, XElement newType, string location) + void AddNewType (XElement sourcePackage, XElement newType, string location, string platform) { var t = AddWithLocation (sourcePackage, newType, location); - AddType (t); + AddType (t, platform); } - void AddNewMember (XElement sourceType, XElement newMember, string location) + void AddNewMember (XElement sourceType, XElement newMember, string location, string platform) { + UpdateDeprecatedSince (newMember, platform); AddWithLocation (sourceType, newMember, location); } XElement GetPackage (string package) { - return Contents.Elements ("api").Elements ("package") + return Contents.Element ("api").Elements ("package") .FirstOrDefault (p => ((string) p.Attribute ("name")) == package); } diff --git a/src/Mono.Android/Profiles/api-10.xml.in b/src/Mono.Android/Profiles/api-10.xml.in index 487482312a9..f0430821235 100644 --- a/src/Mono.Android/Profiles/api-10.xml.in +++ b/src/Mono.Android/Profiles/api-10.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-15.xml.in b/src/Mono.Android/Profiles/api-15.xml.in index 597b611cfcd..2194181be31 100644 --- a/src/Mono.Android/Profiles/api-15.xml.in +++ b/src/Mono.Android/Profiles/api-15.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-16.xml.in b/src/Mono.Android/Profiles/api-16.xml.in index 57d96be0627..c5ecde4bf23 100644 --- a/src/Mono.Android/Profiles/api-16.xml.in +++ b/src/Mono.Android/Profiles/api-16.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-17.xml.in b/src/Mono.Android/Profiles/api-17.xml.in index 8dbdea4fb40..ea3fba267e1 100644 --- a/src/Mono.Android/Profiles/api-17.xml.in +++ b/src/Mono.Android/Profiles/api-17.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-18.xml.in b/src/Mono.Android/Profiles/api-18.xml.in index de928ca1edf..f96b5248036 100644 --- a/src/Mono.Android/Profiles/api-18.xml.in +++ b/src/Mono.Android/Profiles/api-18.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-19.xml.in b/src/Mono.Android/Profiles/api-19.xml.in index a7a9be15c20..21b076b1f07 100644 --- a/src/Mono.Android/Profiles/api-19.xml.in +++ b/src/Mono.Android/Profiles/api-19.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-20.xml.in b/src/Mono.Android/Profiles/api-20.xml.in index b03336de9a1..cc59eaf5406 100644 --- a/src/Mono.Android/Profiles/api-20.xml.in +++ b/src/Mono.Android/Profiles/api-20.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-21.xml.in b/src/Mono.Android/Profiles/api-21.xml.in index 20b54f36c02..f7e41d4de20 100644 --- a/src/Mono.Android/Profiles/api-21.xml.in +++ b/src/Mono.Android/Profiles/api-21.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-22.xml.in b/src/Mono.Android/Profiles/api-22.xml.in index 5b0e9849d24..82bc5d54e76 100644 --- a/src/Mono.Android/Profiles/api-22.xml.in +++ b/src/Mono.Android/Profiles/api-22.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-23.xml.in b/src/Mono.Android/Profiles/api-23.xml.in index 51b3503f141..19308a52d26 100644 --- a/src/Mono.Android/Profiles/api-23.xml.in +++ b/src/Mono.Android/Profiles/api-23.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-24.xml.in b/src/Mono.Android/Profiles/api-24.xml.in index 7672c45a6b4..5a8890b42de 100644 --- a/src/Mono.Android/Profiles/api-24.xml.in +++ b/src/Mono.Android/Profiles/api-24.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-25.xml.in b/src/Mono.Android/Profiles/api-25.xml.in index 8e440e4637c..569b097bf97 100644 --- a/src/Mono.Android/Profiles/api-25.xml.in +++ b/src/Mono.Android/Profiles/api-25.xml.in @@ -1,4 +1,4 @@ - + diff --git a/src/Mono.Android/Profiles/api-26.xml.in b/src/Mono.Android/Profiles/api-26.xml.in index 031fecc0aee..a9dfd561ef0 100644 --- a/src/Mono.Android/Profiles/api-26.xml.in +++ b/src/Mono.Android/Profiles/api-26.xml.in @@ -1,4 +1,4 @@ - +