From 55686d1701c28b6a3957e0a25ab6bdd9aac3d1c6 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Tue, 13 Apr 2021 16:10:23 -0500 Subject: [PATCH 1/2] [generator] Separate metadata fixup step from parsing step. --- .../Extensions/UtilityExtensions.cs | 14 ++ .../Extensions/XmlExtensions.cs | 25 +++ .../Java.Interop.Tools.Generator.csproj | 4 + .../Metadata/FixupXmlDocument.cs | 207 ++++++++++++++++++ .../Utilities/ApiXmlDocument.cs | 47 ++++ .../Utilities}/ISourceLineInfo.cs | 6 +- .../Utilities/Report.cs | 127 ++++++----- .../Unit-Tests/CodeGeneratorTestBase.cs | 2 +- .../Unit-Tests/FixupXmlDocumentTests.cs | 100 +++++++++ .../generator-Tests/Unit-Tests/ReportTests.cs | 1 + .../Unit-Tests/XmlApiImporterTests.cs | 2 +- tools/generator/CodeGenerationOptions.cs | 2 +- tools/generator/CodeGenerator.cs | 24 +- tools/generator/CodeGeneratorOptions.cs | 1 + .../CodeGenerator.cs | 1 + .../XmlApiImporter.cs | 91 ++++++++ .../ClassGen.cs | 1 + .../Field.cs | 2 +- .../GenBase.cs | 1 + .../GenericParameterDefinition.cs | 1 + .../InterfaceGen.cs | 1 + .../MethodBase.cs | 1 + .../Parameter.cs | 1 + .../ReturnValue.cs | 2 +- .../ApiFixup.cs | 1 + .../EnumMap.cs | 1 + .../Parser.cs | 144 ------------ .../Extensions/SourceWriterExtensions.cs | 1 + .../InterfaceMemberAlternativeClass.cs | 1 + 29 files changed, 589 insertions(+), 223 deletions(-) create mode 100644 src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs create mode 100644 src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs create mode 100644 src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs rename {tools/generator/Java.Interop.Tools.Generator.ObjectModel => src/Java.Interop.Tools.Generator/Utilities}/ISourceLineInfo.cs (54%) rename {tools/generator => src/Java.Interop.Tools.Generator}/Utilities/Report.cs (57%) create mode 100644 tests/generator-Tests/Unit-Tests/FixupXmlDocumentTests.cs delete mode 100644 tools/generator/Java.Interop.Tools.Generator.Transformation/Parser.cs diff --git a/src/Java.Interop.Tools.Generator/Extensions/UtilityExtensions.cs b/src/Java.Interop.Tools.Generator/Extensions/UtilityExtensions.cs index 38c8c372a..935885d5d 100644 --- a/src/Java.Interop.Tools.Generator/Extensions/UtilityExtensions.cs +++ b/src/Java.Interop.Tools.Generator/Extensions/UtilityExtensions.cs @@ -1,5 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Xml; +using System.Xml.Linq; namespace Java.Interop.Tools.Generator { @@ -27,5 +29,17 @@ public static bool StartsWithAny (this string value, params string [] values) } public static bool HasValue ([NotNullWhen (true)]this string? str) => !string.IsNullOrEmpty (str); + + public static XDocument? LoadXmlDocument (string filename) + { + try { + return XDocument.Load (filename, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + } catch (XmlException e) { + Report.Verbose (0, "Exception: {0}", e); + Report.LogCodedWarning (0, Report.WarningInvalidXmlFile, e, filename, e.Message); + } + + return null; + } } } diff --git a/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs b/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs new file mode 100644 index 000000000..6e7b36a52 --- /dev/null +++ b/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs @@ -0,0 +1,25 @@ +using System; +using System.Xml.Linq; +using System.Xml.XPath; + +namespace Xamarin.Android.Tools +{ + static class XmlExtensions + { + public static string? XGetAttribute (this XElement element, string name) + => element.Attribute (name)?.Value.Trim (); + + public static string? XGetAttribute (this XPathNavigator nav, string name, string ns) + => nav.GetAttribute (name, ns)?.Trim (); + + public static int? XGetAttributeAsInt (this XElement element, string name) + { + var value = element.XGetAttribute (name); + + if (int.TryParse (value, out var result)) + return result; + + return null; + } + } +} diff --git a/src/Java.Interop.Tools.Generator/Java.Interop.Tools.Generator.csproj b/src/Java.Interop.Tools.Generator/Java.Interop.Tools.Generator.csproj index 8527af75c..11cc6392e 100644 --- a/src/Java.Interop.Tools.Generator/Java.Interop.Tools.Generator.csproj +++ b/src/Java.Interop.Tools.Generator/Java.Interop.Tools.Generator.csproj @@ -15,4 +15,8 @@ + + + + diff --git a/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs b/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs new file mode 100644 index 000000000..c3c39bc10 --- /dev/null +++ b/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs @@ -0,0 +1,207 @@ +using System; +using System.Linq; +using System.Xml.XPath; +using System.Xml.Linq; + +using Xamarin.Android.Tools; + +namespace Java.Interop.Tools.Generator +{ + public class FixupXmlDocument + { + public XDocument FixupDocument { get; } + + public FixupXmlDocument (XDocument fixupDocument) + { + FixupDocument = fixupDocument; + } + + public static FixupXmlDocument? Load (string filename) + { + if (UtilityExtensions.LoadXmlDocument (filename) is XDocument doc) + return new FixupXmlDocument (doc); + + return null; + } + + public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int productVersion) + { + // Defaulting to 0 here is fine + int.TryParse (apiLevelString, out var apiLevel); + + var metadataChildren = FixupDocument.XPathSelectElements ("/metadata/*"); + + string? prev_path = null; + XElement? attr_last_cache = null; + + foreach (var metaitem in metadataChildren) { + if (ShouldSkip (metaitem, apiLevel, productVersion)) + continue; + if (!ShouldApply (metaitem, apiDocument)) + continue; + + var path = metaitem.XGetAttribute ("path"); + + if (path != prev_path) + attr_last_cache = null; + + prev_path = path; + + switch (metaitem.Name.LocalName) { + case "remove-node": + try { + var nodes = apiDocument.ApiDocument.XPathSelectElements (path).ToArray (); + + if (nodes.Any ()) + foreach (var node in nodes) + node.Remove (); + else + // BG8A00 + Report.LogCodedWarning (0, Report.WarningRemoveNodeMatchedNoNodes, null, metaitem, $""); + } catch (XPathException e) { + // BG4301 + Report.LogCodedError (Report.ErrorRemoveNodeInvalidXPath, e, metaitem, path); + } + break; + case "add-node": + try { + var nodes = apiDocument.ApiDocument.XPathSelectElements (path); + + if (!nodes.Any ()) + // BG8A01 + Report.LogCodedWarning (0, Report.WarningAddNodeMatchedNoNodes, null, metaitem, $""); + else { + foreach (var node in nodes) + node.Add (metaitem.Nodes ()); + } + } catch (XPathException e) { + // BG4302 + Report.LogCodedError (Report.ErrorAddNodeInvalidXPath, e, metaitem, path); + } + break; + case "change-node": + try { + var nodes = apiDocument.ApiDocument.XPathSelectElements (path); + var matched = false; + + foreach (var node in nodes) { + var newChild = new XElement (metaitem.Value); + newChild.Add (node.Attributes ()); + newChild.Add (node.Nodes ()); + node.ReplaceWith (newChild); + matched = true; + } + + if (!matched) + // BG8A03 + Report.LogCodedWarning (0, Report.WarningChangeNodeTypeMatchedNoNodes, null, metaitem, $""); + } catch (XPathException e) { + // BG4303 + Report.LogCodedError (Report.ErrorChangeNodeInvalidXPath, e, metaitem, path); + } + break; + case "attr": + try { + var attr_name = metaitem.XGetAttribute ("name"); + + if (string.IsNullOrEmpty (attr_name)) + // BG4307 + Report.LogCodedError (Report.ErrorMissingAttrName, null, metaitem, path); + var nodes = attr_last_cache != null ? new XElement [] { attr_last_cache } : apiDocument.ApiDocument.XPathSelectElements (path); + var attr_matched = 0; + + foreach (var n in nodes) { + n.SetAttributeValue (attr_name, metaitem.Value); + attr_matched++; + } + if (attr_matched == 0) + // BG8A04 + Report.LogCodedWarning (0, Report.WarningAttrMatchedNoNodes, null, metaitem, $""); + if (attr_matched != 1) + attr_last_cache = null; + } catch (XPathException e) { + // BG4304 + Report.LogCodedError (Report.ErrorAttrInvalidXPath, e, metaitem, path); + } + break; + case "move-node": + try { + var parent = metaitem.Value; + var parents = apiDocument.ApiDocument.XPathSelectElements (parent); + var matched = false; + + foreach (var parent_node in parents) { + var nodes = parent_node.XPathSelectElements (path).ToArray (); + foreach (var node in nodes) + node.Remove (); + parent_node.Add (nodes); + matched = true; + } + if (!matched) + // BG8A05 + Report.LogCodedWarning (0, Report.WarningMoveNodeMatchedNoNodes, null, metaitem, $""); + } catch (XPathException e) { + // BG4305 + Report.LogCodedError (Report.ErrorMoveNodeInvalidXPath, e, metaitem, path); + } + break; + case "remove-attr": + try { + var name = metaitem.XGetAttribute ("name"); + var nodes = apiDocument.ApiDocument.XPathSelectElements (path); + var matched = false; + + foreach (var node in nodes) { + node.RemoveAttributes (); + matched = true; + } + + if (!matched) + // BG8A06 + Report.LogCodedWarning (0, Report.WarningRemoveAttrMatchedNoNodes, null, metaitem, $""); + } catch (XPathException e) { + // BG4306 + Report.LogCodedError (Report.ErrorRemoveAttrInvalidXPath, e, metaitem, path); + } + break; + } + } + } + + bool ShouldSkip (XElement node, int apiLevel, int productVersion) + { + if (apiLevel > 0) { + var since = node.XGetAttributeAsInt ("api-since"); + var until = node.XGetAttributeAsInt ("api-until"); + + if (since is int since_int && since_int > apiLevel) + return true; + else if (until is int until_int && until_int < apiLevel) + return true; + } + + if (productVersion > 0) { + var product_version = node.XGetAttributeAsInt ("product-version"); + + if (product_version is int version && version > productVersion) + return true; + + } + return false; + } + + bool ShouldApply (XElement node, ApiXmlDocument apiDocument) + { + if (apiDocument.ApiSource.HasValue ()) { + var targetsource = node.XGetAttribute ("api-source"); + + if (!targetsource.HasValue ()) + return true; + + return targetsource == apiDocument.ApiSource; + } + + return true; + } + } +} diff --git a/src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs b/src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs new file mode 100644 index 000000000..1bd333165 --- /dev/null +++ b/src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs @@ -0,0 +1,47 @@ +using System; +using System.Xml; +using System.Xml.Linq; +using Xamarin.Android.Tools; + +namespace Java.Interop.Tools.Generator +{ + public class ApiXmlDocument + { + public XDocument ApiDocument { get; } + public string ApiLevel { get; } + public int ProductVersion { get; } + + public string? ApiSource => ApiDocument.Root?.XGetAttribute ("api-source"); + + public ApiXmlDocument (XDocument document, string apiLevel, int productVersion) + { + ApiDocument = document; + ApiLevel = apiLevel; + ProductVersion = productVersion; + } + + public static ApiXmlDocument? Load (string filename, string apiLevel, int productVersion) + { + if (UtilityExtensions.LoadXmlDocument (filename) is XDocument doc) + return new ApiXmlDocument (doc, apiLevel, productVersion); + + return null; + } + + public void ApplyFixupFile (string filename) + { + if (FixupXmlDocument.Load (filename) is FixupXmlDocument fixup) + ApplyFixupFile (fixup); + } + + public void ApplyFixupFile (FixupXmlDocument fixup) + { + try { + fixup.Apply (this, ApiLevel, ProductVersion); + } catch (XmlException ex) { + // BG4200 + Report.LogCodedError (Report.ErrorFailedToProcessMetadata, ex.Message); + } + } + } +} diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ISourceLineInfo.cs b/src/Java.Interop.Tools.Generator/Utilities/ISourceLineInfo.cs similarity index 54% rename from tools/generator/Java.Interop.Tools.Generator.ObjectModel/ISourceLineInfo.cs rename to src/Java.Interop.Tools.Generator/Utilities/ISourceLineInfo.cs index 1c0fec851..9ef4ae09c 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ISourceLineInfo.cs +++ b/src/Java.Interop.Tools.Generator/Utilities/ISourceLineInfo.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace MonoDroid.Generation +namespace Java.Interop.Tools.Generator { public interface ISourceLineInfo { diff --git a/tools/generator/Utilities/Report.cs b/src/Java.Interop.Tools.Generator/Utilities/Report.cs similarity index 57% rename from tools/generator/Utilities/Report.cs rename to src/Java.Interop.Tools.Generator/Utilities/Report.cs index 127f7fc21..e216a1535 100644 --- a/tools/generator/Utilities/Report.cs +++ b/src/Java.Interop.Tools.Generator/Utilities/Report.cs @@ -2,7 +2,7 @@ using System.Xml; using System.Xml.Linq; -namespace MonoDroid.Generation +namespace Java.Interop.Tools.Generator { public class Report { @@ -20,62 +20,62 @@ public LocalizedMessage (int code, string value) } } - public static LocalizedMessage ErrorFailedToRemoveConstants => new LocalizedMessage (0x4000, Java.Interop.Localization.Resources.Generator_BG4000); - public static LocalizedMessage ErrorFailedToProcessEnumMap => new LocalizedMessage (0x4100, Java.Interop.Localization.Resources.Generator_BG4100); - public static LocalizedMessage ErrorFailedToProcessMetadata => new LocalizedMessage (0x4200, Java.Interop.Localization.Resources.Generator_BG4200); - public static LocalizedMessage ErrorRemoveNodeInvalidXPath => new LocalizedMessage (0x4301, Java.Interop.Localization.Resources.Generator_BG4300); - public static LocalizedMessage ErrorAddNodeInvalidXPath => new LocalizedMessage (0x4302, Java.Interop.Localization.Resources.Generator_BG4300); - public static LocalizedMessage ErrorChangeNodeInvalidXPath => new LocalizedMessage (0x4303, Java.Interop.Localization.Resources.Generator_BG4300); - public static LocalizedMessage ErrorAttrInvalidXPath => new LocalizedMessage (0x4304, Java.Interop.Localization.Resources.Generator_BG4300); - public static LocalizedMessage ErrorMoveNodeInvalidXPath => new LocalizedMessage (0x4305, Java.Interop.Localization.Resources.Generator_BG4300); - public static LocalizedMessage ErrorRemoveAttrInvalidXPath => new LocalizedMessage (0x4306, Java.Interop.Localization.Resources.Generator_BG4300); - public static LocalizedMessage ErrorMissingAttrName => new LocalizedMessage (0x4307, Java.Interop.Localization.Resources.Generator_BG4307); - public static LocalizedMessage ErrorUnexpectedGlobal => new LocalizedMessage (0x4400, Java.Interop.Localization.Resources.Generator_BG4400); - public static LocalizedMessage ErrorInvalidDIMArgument => new LocalizedMessage (0x4500, Java.Interop.Localization.Resources.Generator_BG4500); - - public static LocalizedMessage WarningUnexpectedChild => new LocalizedMessage (0x8101, Java.Interop.Localization.Resources.Generator_BG8101); - public static LocalizedMessage WarningUnknownBaseType => new LocalizedMessage (0x8102, Java.Interop.Localization.Resources.Generator_BG8102); - public static LocalizedMessage WarningInvalidBaseType => new LocalizedMessage (0x8103, Java.Interop.Localization.Resources.Generator_BG8103); - public static LocalizedMessage WarningAssemblyParseFailure => new LocalizedMessage (0x8200, Java.Interop.Localization.Resources.Generator_BG8200); - public static LocalizedMessage WarningMissingClassForConstructor => new LocalizedMessage (0x8300, Java.Interop.Localization.Resources.Generator_BG8300); - public static LocalizedMessage WarningUnexpectedFieldType => new LocalizedMessage (0x8400, Java.Interop.Localization.Resources.Generator_BG8400); - public static LocalizedMessage WarningFieldNameCollision_Property => new LocalizedMessage (0x8401, Java.Interop.Localization.Resources.Generator_BG8401_Property); - public static LocalizedMessage WarningFieldNameCollision_Method => new LocalizedMessage (0x8401, Java.Interop.Localization.Resources.Generator_BG8401_Method); - public static LocalizedMessage WarningFieldNameCollision_NestedType => new LocalizedMessage (0x8401, Java.Interop.Localization.Resources.Generator_BG8401_NestedType); - public static LocalizedMessage WarningDuplicateField => new LocalizedMessage (0x8402, Java.Interop.Localization.Resources.Generator_BG8402); - public static LocalizedMessage WarningUnexpectedInterfaceChild => new LocalizedMessage (0x8500, Java.Interop.Localization.Resources.Generator_BG8500); - public static LocalizedMessage WarningEmptyEventName => new LocalizedMessage (0x8501, Java.Interop.Localization.Resources.Generator_BG8501); - public static LocalizedMessage WarningInvalidDueToInterfaces => new LocalizedMessage (0x8502, Java.Interop.Localization.Resources.Generator_BG8502); - public static LocalizedMessage WarningInvalidDueToMethods => new LocalizedMessage (0x8503, Java.Interop.Localization.Resources.Generator_BG8503); - public static LocalizedMessage WarningInvalidEventName => new LocalizedMessage (0x8504, Java.Interop.Localization.Resources.Generator_BG8504); - public static LocalizedMessage WarningInvalidEventName2 => new LocalizedMessage (0x8505, Java.Interop.Localization.Resources.Generator_BG8504); - public static LocalizedMessage WarningInvalidEventPropertyName => new LocalizedMessage (0x8506, Java.Interop.Localization.Resources.Generator_BG8506); - public static LocalizedMessage WarningInvalidXmlFile => new LocalizedMessage (0x8600, Java.Interop.Localization.Resources.Generator_BG8600); - public static LocalizedMessage WarningNoPackageElements => new LocalizedMessage (0x8601, Java.Interop.Localization.Resources.Generator_BG8601); - public static LocalizedMessage WarningUnexpectedRootChildNode => new LocalizedMessage (0x8602, Java.Interop.Localization.Resources.Generator_BG8602); - public static LocalizedMessage WarningUnexpectedPackageChildNode => new LocalizedMessage (0x8603, Java.Interop.Localization.Resources.Generator_BG8603); - public static LocalizedMessage WarningNestedTypeAncestorNotFound => new LocalizedMessage (0x8604, Java.Interop.Localization.Resources.Generator_BG8604); - public static LocalizedMessage WarningUnknownReturnType => new LocalizedMessage (0x8700, Java.Interop.Localization.Resources.Generator_BG8700); - public static LocalizedMessage WarningInvalidReturnType => new LocalizedMessage (0x8701, Java.Interop.Localization.Resources.Generator_BG8701); - public static LocalizedMessage WarningUnknownParameterType => new LocalizedMessage (0x8800, Java.Interop.Localization.Resources.Generator_BG8800); - public static LocalizedMessage WarningInvalidParameterType => new LocalizedMessage (0x8801, Java.Interop.Localization.Resources.Generator_BG8801); - public static LocalizedMessage WarningRemoveNodeMatchedNoNodes => new LocalizedMessage (0x8A00, Java.Interop.Localization.Resources.Generator_BG8A00); - public static LocalizedMessage WarningAddNodeMatchedNoNodes => new LocalizedMessage (0x8A01, Java.Interop.Localization.Resources.Generator_BG8A00); - public static LocalizedMessage WarningChangeNodeTypeMatchedNoNodes => new LocalizedMessage (0x8A03, Java.Interop.Localization.Resources.Generator_BG8A00); - public static LocalizedMessage WarningAttrMatchedNoNodes => new LocalizedMessage (0x8A04, Java.Interop.Localization.Resources.Generator_BG8A00); - public static LocalizedMessage WarningMoveNodeMatchedNoNodes => new LocalizedMessage (0x8A05, Java.Interop.Localization.Resources.Generator_BG8A00); - public static LocalizedMessage WarningRemoveAttrMatchedNoNodes => new LocalizedMessage (0x8A06, Java.Interop.Localization.Resources.Generator_BG8A00); - public static LocalizedMessage WarningUnknownGenericConstraint => new LocalizedMessage (0x8B00, Java.Interop.Localization.Resources.Generator_BG8B00); - public static LocalizedMessage WarningBaseInterfaceNotFound => new LocalizedMessage (0x8C00, Java.Interop.Localization.Resources.Generator_BG8C00); - public static LocalizedMessage WarningBaseInterfaceInvalid => new LocalizedMessage (0x8C01, Java.Interop.Localization.Resources.Generator_BG8C01); + public static LocalizedMessage ErrorFailedToRemoveConstants => new LocalizedMessage (0x4000, Localization.Resources.Generator_BG4000); + public static LocalizedMessage ErrorFailedToProcessEnumMap => new LocalizedMessage (0x4100, Localization.Resources.Generator_BG4100); + public static LocalizedMessage ErrorFailedToProcessMetadata => new LocalizedMessage (0x4200, Localization.Resources.Generator_BG4200); + public static LocalizedMessage ErrorRemoveNodeInvalidXPath => new LocalizedMessage (0x4301, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorAddNodeInvalidXPath => new LocalizedMessage (0x4302, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorChangeNodeInvalidXPath => new LocalizedMessage (0x4303, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorAttrInvalidXPath => new LocalizedMessage (0x4304, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorMoveNodeInvalidXPath => new LocalizedMessage (0x4305, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorRemoveAttrInvalidXPath => new LocalizedMessage (0x4306, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorMissingAttrName => new LocalizedMessage (0x4307, Localization.Resources.Generator_BG4307); + public static LocalizedMessage ErrorUnexpectedGlobal => new LocalizedMessage (0x4400, Localization.Resources.Generator_BG4400); + public static LocalizedMessage ErrorInvalidDIMArgument => new LocalizedMessage (0x4500, Localization.Resources.Generator_BG4500); + + public static LocalizedMessage WarningUnexpectedChild => new LocalizedMessage (0x8101, Localization.Resources.Generator_BG8101); + public static LocalizedMessage WarningUnknownBaseType => new LocalizedMessage (0x8102, Localization.Resources.Generator_BG8102); + public static LocalizedMessage WarningInvalidBaseType => new LocalizedMessage (0x8103, Localization.Resources.Generator_BG8103); + public static LocalizedMessage WarningAssemblyParseFailure => new LocalizedMessage (0x8200, Localization.Resources.Generator_BG8200); + public static LocalizedMessage WarningMissingClassForConstructor => new LocalizedMessage (0x8300, Localization.Resources.Generator_BG8300); + public static LocalizedMessage WarningUnexpectedFieldType => new LocalizedMessage (0x8400, Localization.Resources.Generator_BG8400); + public static LocalizedMessage WarningFieldNameCollision_Property => new LocalizedMessage (0x8401, Localization.Resources.Generator_BG8401_Property); + public static LocalizedMessage WarningFieldNameCollision_Method => new LocalizedMessage (0x8401, Localization.Resources.Generator_BG8401_Method); + public static LocalizedMessage WarningFieldNameCollision_NestedType => new LocalizedMessage (0x8401, Localization.Resources.Generator_BG8401_NestedType); + public static LocalizedMessage WarningDuplicateField => new LocalizedMessage (0x8402, Localization.Resources.Generator_BG8402); + public static LocalizedMessage WarningUnexpectedInterfaceChild => new LocalizedMessage (0x8500, Localization.Resources.Generator_BG8500); + public static LocalizedMessage WarningEmptyEventName => new LocalizedMessage (0x8501, Localization.Resources.Generator_BG8501); + public static LocalizedMessage WarningInvalidDueToInterfaces => new LocalizedMessage (0x8502, Localization.Resources.Generator_BG8502); + public static LocalizedMessage WarningInvalidDueToMethods => new LocalizedMessage (0x8503, Localization.Resources.Generator_BG8503); + public static LocalizedMessage WarningInvalidEventName => new LocalizedMessage (0x8504, Localization.Resources.Generator_BG8504); + public static LocalizedMessage WarningInvalidEventName2 => new LocalizedMessage (0x8505, Localization.Resources.Generator_BG8504); + public static LocalizedMessage WarningInvalidEventPropertyName => new LocalizedMessage (0x8506, Localization.Resources.Generator_BG8506); + public static LocalizedMessage WarningInvalidXmlFile => new LocalizedMessage (0x8600, Localization.Resources.Generator_BG8600); + public static LocalizedMessage WarningNoPackageElements => new LocalizedMessage (0x8601, Localization.Resources.Generator_BG8601); + public static LocalizedMessage WarningUnexpectedRootChildNode => new LocalizedMessage (0x8602, Localization.Resources.Generator_BG8602); + public static LocalizedMessage WarningUnexpectedPackageChildNode => new LocalizedMessage (0x8603, Localization.Resources.Generator_BG8603); + public static LocalizedMessage WarningNestedTypeAncestorNotFound => new LocalizedMessage (0x8604, Localization.Resources.Generator_BG8604); + public static LocalizedMessage WarningUnknownReturnType => new LocalizedMessage (0x8700, Localization.Resources.Generator_BG8700); + public static LocalizedMessage WarningInvalidReturnType => new LocalizedMessage (0x8701, Localization.Resources.Generator_BG8701); + public static LocalizedMessage WarningUnknownParameterType => new LocalizedMessage (0x8800, Localization.Resources.Generator_BG8800); + public static LocalizedMessage WarningInvalidParameterType => new LocalizedMessage (0x8801, Localization.Resources.Generator_BG8801); + public static LocalizedMessage WarningRemoveNodeMatchedNoNodes => new LocalizedMessage (0x8A00, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningAddNodeMatchedNoNodes => new LocalizedMessage (0x8A01, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningChangeNodeTypeMatchedNoNodes => new LocalizedMessage (0x8A03, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningAttrMatchedNoNodes => new LocalizedMessage (0x8A04, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningMoveNodeMatchedNoNodes => new LocalizedMessage (0x8A05, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningRemoveAttrMatchedNoNodes => new LocalizedMessage (0x8A06, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningUnknownGenericConstraint => new LocalizedMessage (0x8B00, Localization.Resources.Generator_BG8B00); + public static LocalizedMessage WarningBaseInterfaceNotFound => new LocalizedMessage (0x8C00, Localization.Resources.Generator_BG8C00); + public static LocalizedMessage WarningBaseInterfaceInvalid => new LocalizedMessage (0x8C01, Localization.Resources.Generator_BG8C01); public static void LogCodedError (LocalizedMessage message, params string [] args) => LogCodedError (message, null, null, -1, -1, args); - public static void LogCodedError (LocalizedMessage message, Exception innerException, params string [] args) + public static void LogCodedError (LocalizedMessage message, Exception? innerException, params string [] args) => LogCodedError (message, innerException, null, -1, -1, args); - public static void LogCodedError (LocalizedMessage message, Exception innerException, XNode node, params string [] args) + public static void LogCodedError (LocalizedMessage message, Exception? innerException, XNode node, params string? [] args) { var file = Uri.TryCreate (node.BaseUri, UriKind.Absolute, out var uri) ? uri.LocalPath : null; var line_info = (node as IXmlLineInfo)?.HasLineInfo () == true ? node as IXmlLineInfo : null; @@ -83,21 +83,21 @@ public static void LogCodedError (LocalizedMessage message, Exception innerExcep LogCodedError (message, innerException, file, line_info?.LineNumber ?? -1, line_info?.LinePosition ?? -1, args); } - public static void LogCodedError (LocalizedMessage message, Exception innerException, string sourceFile, int line, int column, params string [] args) + public static void LogCodedError (LocalizedMessage message, Exception? innerException, string? sourceFile, int line, int column, params string? [] args) { throw new BindingGeneratorException (message.Code, sourceFile, line, column, string.Format (message.Value, args), innerException); } - public static void LogCodedWarning (int verbosity, LocalizedMessage message, params string [] args) + public static void LogCodedWarning (int verbosity, LocalizedMessage message, params string? [] args) => LogCodedWarning (verbosity, message, null, null, -1, -1, args); - public static void LogCodedWarning (int verbosity, LocalizedMessage message, ISourceLineInfo sourceInfo, params string [] args) + public static void LogCodedWarning (int verbosity, LocalizedMessage message, ISourceLineInfo sourceInfo, params string? [] args) => LogCodedWarning (verbosity, message, null, sourceInfo.SourceFile, sourceInfo.LineNumber, sourceInfo.LinePosition, args); - public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exception innerException, params string [] args) + public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exception? innerException, params string? [] args) => LogCodedWarning (verbosity, message, innerException, null, -1, -1, args); - public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exception innerException, XNode node, params string [] args) + public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exception? innerException, XNode node, params string? [] args) { var file = Uri.TryCreate (node.BaseUri, UriKind.Absolute, out var uri) ? uri.LocalPath : null; var line_info = (node as IXmlLineInfo)?.HasLineInfo () == true ? node as IXmlLineInfo : null; @@ -105,7 +105,7 @@ public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exc LogCodedWarning (verbosity, message, innerException, file, line_info?.LineNumber ?? -1, line_info?.LinePosition ?? -1, args); } - public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exception innerException, string sourceFile, int line, int column, params string [] args) + public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exception? innerException, string? sourceFile, int line, int column, params string? [] args) { if (verbosity > (Verbosity ?? 0)) return; @@ -117,24 +117,24 @@ public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exc Console.Error.WriteLine (innerException); } - public static void Verbose (int verbosity, string format, params object[] args) + public static void Verbose (int verbosity, string format, params object?[] args) { if (verbosity > (Verbosity ?? 0)) return; Console.Error.WriteLine (format, args); } - public static string FormatCodedMessage (bool error, LocalizedMessage message, params object [] args) + public static string FormatCodedMessage (bool error, LocalizedMessage message, params object? [] args) => Format (error, message.Code, null, -1, -1, message.Value, args); - public static string Format (bool error, int errorCode, string sourceFile, int line, int column, string format, params object[] args) + public static string Format (bool error, int errorCode, string? sourceFile, int line, int column, string format, params object?[] args) { var origin = FormatOrigin (sourceFile, line, column); return $"{origin}{(error ? "error" : "warning")} BG{errorCode:X04}: " + string.Format (format, args); } - static string FormatOrigin (string sourceFile, int line, int column) + static string? FormatOrigin (string? sourceFile, int line, int column) { if (string.IsNullOrWhiteSpace (sourceFile)) return null; @@ -157,14 +157,13 @@ public BindingGeneratorException (int errorCode, string message) : this (errorCode, message, null) { } - public BindingGeneratorException (int errorCode, string message, Exception innerException) + public BindingGeneratorException (int errorCode, string message, Exception? innerException) : this (errorCode, null, -1, -1, message, innerException) { } - public BindingGeneratorException (int errorCode, string sourceFile, int line, int column, string message, Exception innerException) + public BindingGeneratorException (int errorCode, string? sourceFile, int line, int column, string message, Exception? innerException) : base (Report.Format (true, errorCode, sourceFile, line, column, message), innerException) { } } } - diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs b/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs index f3435d3f7..5d1abdb06 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs @@ -62,7 +62,7 @@ string GetExpectedResults (string testName, string target) protected List ParseApiDefinition (string xml) { var doc = XDocument.Parse (xml); - var gens = new Parser (options).Parse (doc, Enumerable.Empty (), "29", 7); + var gens = XmlApiImporter.Parse (doc, options); foreach (var gen in gens) options.SymbolTable.AddType (gen); diff --git a/tests/generator-Tests/Unit-Tests/FixupXmlDocumentTests.cs b/tests/generator-Tests/Unit-Tests/FixupXmlDocumentTests.cs new file mode 100644 index 000000000..5ce1c72e1 --- /dev/null +++ b/tests/generator-Tests/Unit-Tests/FixupXmlDocumentTests.cs @@ -0,0 +1,100 @@ +using System; +using System.Xml.Linq; +using Java.Interop.Tools.Generator; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class FixupXmlDocumentTests + { + [Test] + public void RemoveNode () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument (""); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void AddNode () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument (""); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void ChangeNode () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument ("method"); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void MoveNode () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument ("/api/package[@name='android']"); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void SetNewAttribute () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument ("true"); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void ChangeAttribute () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument ("android2"); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void RemoveAttribute () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument (""); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + ApiXmlDocument GetXmlApiDocument () + { + var api = ""; + + return new ApiXmlDocument (XDocument.Parse (api), "30", 0); + } + + FixupXmlDocument GetFixupXmlDocument (string text) + { + return new FixupXmlDocument (XDocument.Parse ("" + text + "")); + } + } +} diff --git a/tests/generator-Tests/Unit-Tests/ReportTests.cs b/tests/generator-Tests/Unit-Tests/ReportTests.cs index bd04a850d..cdb4925df 100644 --- a/tests/generator-Tests/Unit-Tests/ReportTests.cs +++ b/tests/generator-Tests/Unit-Tests/ReportTests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Java.Interop.Tools.Generator; using MonoDroid.Generation; using NUnit.Framework; diff --git a/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs b/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs index 77b0ccb1a..ba91ba96e 100644 --- a/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs +++ b/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs @@ -260,7 +260,7 @@ public void IgnoreKotlinInternalMembers () "); - var gens = new Parser (opt).Parse (xml, new List (), "0", 0); + var gens = XmlApiImporter.Parse (xml, opt); var klass = gens.Single (); Assert.AreEqual (0, klass.Fields.Count); diff --git a/tools/generator/CodeGenerationOptions.cs b/tools/generator/CodeGenerationOptions.cs index a2a3690bf..515b3585d 100644 --- a/tools/generator/CodeGenerationOptions.cs +++ b/tools/generator/CodeGenerationOptions.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Text; - +using Java.Interop.Tools.Generator; using Java.Interop.Tools.JavaCallableWrappers; using Xamarin.Android.Binder; diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index 720582879..2f8fc1cc8 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -14,6 +14,7 @@ using Java.Interop.Tools.TypeNameMappings; using MonoDroid.Generation.Utilities; using Java.Interop.Tools.Generator.Transformation; +using Java.Interop.Tools.Generator; namespace Xamarin.Android.Binder { @@ -139,12 +140,25 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve fixups.Add (enum_metadata); } - Parser p = new Parser (opt); - List gens = p.Parse (apiXmlFile, fixups, api_level, product_version); - if (gens == null) { + // Load the API XML document + var api = ApiXmlDocument.Load (apiXmlFile, api_level, product_version); + + if (api is null) return; - } - apiSource = p.ApiSource; + + // Apply metadata fixups + foreach (var fixup in fixups) + api.ApplyFixupFile (fixup); + + api.ApiDocument.Save (apiXmlFile + ".fixed"); + + // Parse API XML + var gens = XmlApiImporter.Parse (api.ApiDocument, opt); + + if (gens is null) + return; + + apiSource = api.ApiSource; // disable interface default methods here, especially before validation. gens = gens.Where (g => !g.IsObfuscated && g.Visibility != "private").ToList (); diff --git a/tools/generator/CodeGeneratorOptions.cs b/tools/generator/CodeGeneratorOptions.cs index 8a601d4e2..81d42ff79 100644 --- a/tools/generator/CodeGeneratorOptions.cs +++ b/tools/generator/CodeGeneratorOptions.cs @@ -6,6 +6,7 @@ using Java.Interop.Tools.JavaSource; using MonoDroid.Generation; +using Java.Interop.Tools.Generator; namespace Xamarin.Android.Binder { diff --git a/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs b/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs index 29fbb3e3a..f7cbfa234 100644 --- a/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs +++ b/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text; using generator.SourceWriters; +using Java.Interop.Tools.Generator; using Xamarin.Android.Binder; namespace MonoDroid.Generation diff --git a/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs b/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs index e526a73e0..317e6a282 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; +using Java.Interop.Tools.Generator; using Java.Interop.Tools.JavaCallableWrappers; using MonoDroid.Utils; using Xamarin.Android.Tools; @@ -13,6 +15,95 @@ class XmlApiImporter { static readonly Regex api_level = new Regex (@"api-(\d+).xml"); + public static List Parse (XDocument doc, CodeGenerationOptions options) + { + if (doc is null) + return null; + + var root = doc.Root; + + if ((root == null) || !root.HasElements) { + Report.LogCodedWarning (0, Report.WarningNoPackageElements); + return null; + } + + var gens = new List (); + + foreach (var elem in root.Elements ()) { + switch (elem.Name.LocalName) { + case "package": + gens.AddRange (ParsePackage (elem, options)); + break; + case "enum": + var sym = new EnumSymbol (elem.XGetAttribute ("name")); + options.SymbolTable.AddType (elem.XGetAttribute ("name"), sym); + continue; + default: + Report.LogCodedWarning (0, Report.WarningUnexpectedRootChildNode, elem.Name.ToString ()); + break; + } + } + + return gens; + } + + public static List ParsePackage (XElement ns, CodeGenerationOptions options) + { + var result = new List (); + var nested = new Dictionary (); + var by_name = new Dictionary (); + + foreach (var elem in ns.Elements ()) { + + var name = elem.XGetAttribute ("name"); + GenBase gen = null; + + switch (elem.Name.LocalName) { + case "class": + if (elem.XGetAttribute ("obfuscated") == "true") + continue; + gen = CreateClass (ns, elem, options); + break; + case "interface": + if (elem.XGetAttribute ("obfuscated") == "true") + continue; + gen = CreateInterface (ns, elem, options); + break; + default: + Report.LogCodedWarning (0, Report.WarningUnexpectedPackageChildNode, elem.Name.ToString ()); + break; + } + + if (gen is null) + continue; + + var idx = name.IndexOf ('<'); + + if (idx > 0) + name = name.Substring (0, idx); + + by_name [name] = gen; + + if (name.IndexOf ('.') > 0) + nested [name] = gen; + else + result.Add (gen); + } + + foreach (var name in nested.Keys) { + var top_ancestor = name.Substring (0, name.IndexOf ('.')); + + if (by_name.ContainsKey (top_ancestor)) + by_name [top_ancestor].AddNestedType (nested [name]); + else { + Report.LogCodedWarning (0, Report.WarningNestedTypeAncestorNotFound, top_ancestor, nested [name].FullName); + nested [name].Invalidate (); + } + } + + return result; + } + public static ClassGen CreateClass (XElement pkg, XElement elem, CodeGenerationOptions options) { var klass = new ClassGen (CreateGenBaseSupport (pkg, elem, false)) { diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs index e65a9f296..7d31ba635 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Java.Interop.Tools.Generator; using Java.Interop.Tools.TypeNameMappings; using Xamarin.Android.Binder; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs index a3ded000b..da6b2423d 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using MonoDroid.Utils; +using Java.Interop.Tools.Generator; namespace MonoDroid.Generation { diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs index 75003763f..609b027cf 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using Java.Interop.Tools.Generator; using MonoDroid.Generation.Utilities; namespace MonoDroid.Generation diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs index 9cf846206..e4a39e9ea 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs @@ -5,6 +5,7 @@ using System.Xml; using System.Xml.Linq; using System.Xml.XPath; +using Java.Interop.Tools.Generator; using Mono.Cecil; using Xamarin.Android.Tools; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs index d7f5f4162..6158c9f57 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Java.Interop.Tools.Generator; using Xamarin.Android.Binder; namespace MonoDroid.Generation diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs index b43a2cea8..a9222d4ca 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Text; +using Java.Interop.Tools.Generator; using MonoDroid.Generation.Utilities; namespace MonoDroid.Generation diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs index 1fc7eb870..1c79726e0 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Xml; using System.Xml.Linq; +using Java.Interop.Tools.Generator; using Mono.Cecil; using Xamarin.Android.Binder; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs index efb07e660..55d989d6a 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Xml; - +using Java.Interop.Tools.Generator; using MonoDroid.Utils; namespace MonoDroid.Generation { diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiFixup.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiFixup.cs index 7dc1f38ec..f9500d368 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiFixup.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiFixup.cs @@ -6,6 +6,7 @@ using System.Xml.Linq; using Xamarin.Android.Tools; +using Java.Interop.Tools.Generator; namespace MonoDroid.Generation { diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs index dc6250bb7..43d6f6513 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs @@ -5,6 +5,7 @@ using System.Xml; using Xamarin.Android; +using Java.Interop.Tools.Generator; namespace MonoDroid.Generation { diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/Parser.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/Parser.cs deleted file mode 100644 index 3ca272bc3..000000000 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/Parser.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Xml; -using System.Xml.Linq; -using Xamarin.Android.Tools; - -namespace MonoDroid.Generation -{ - public class Parser - { - readonly CodeGenerationOptions opt; - - public Parser (CodeGenerationOptions opt) - { - this.opt = opt; - } - - public string ApiSource { get; private set; } - - public XDocument Load (string filename) - { - XDocument doc = null; - - try { - doc = XDocument.Load (filename, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); - } catch (XmlException e) { - Report.Verbose (0, "Exception: {0}", e); - Report.LogCodedWarning (0, Report.WarningInvalidXmlFile, e, filename, e.Message); - } - - return doc; - } - - public List Parse (string filename, IEnumerable fixups, string apiLevel, int productVersion) - { - var doc = Load (filename); - try { - return Parse (doc, fixups, apiLevel, productVersion); - } finally { - try { - doc.Save (filename + ".fixed"); - } catch { } // skip any error here. - } - } - - public List Parse (XDocument doc, IEnumerable fixups, string apiLevel, int productVersion) - { - if (doc == null) - return null; - try { - var apiFixup = new ApiFixup (doc); - apiFixup.Process (from fixup in fixups select Load (fixup), apiLevel, productVersion); - ApiSource = apiFixup.ApiSource; - } catch (XmlException ex) { - // BG4200 - Report.LogCodedError (Report.ErrorFailedToProcessMetadata, ex.Message); - return null; - } - - var root = doc.Root; - - if ((root == null) || !root.HasElements) { - Report.LogCodedWarning (0, Report.WarningNoPackageElements); - return null; - } - - List gens = new List (); - - foreach (var elem in root.Elements ()) { - switch (elem.Name.LocalName) { - case "package": - gens.AddRange (ParsePackage (elem)); - break; - case "enum": - ISymbol sym = new EnumSymbol (elem.XGetAttribute ("name")); - opt.SymbolTable.AddType (elem.XGetAttribute ("name"), sym); - continue; - default: - Report.LogCodedWarning (0, Report.WarningUnexpectedRootChildNode, elem.Name.ToString ()); - break; - } - } - - return gens; - } - - List ParsePackage (XElement ns) - { - return ParsePackage (ns, null); - } - - List ParsePackage (XElement ns, Predicate p) - { - List result = new List (); - Dictionary nested = new Dictionary (); - Dictionary by_name = new Dictionary (); - - foreach (var elem in ns.Elements ()) { - - string name = elem.XGetAttribute ("name"); - GenBase gen = null; - switch (elem.Name.LocalName) { - case "class": - if (elem.XGetAttribute ("obfuscated") == "true") - continue; - gen = XmlApiImporter.CreateClass (ns, elem, opt); - break; - case "interface": - if (elem.XGetAttribute ("obfuscated") == "true") - continue; - gen = XmlApiImporter.CreateInterface (ns, elem, opt); - break; - default: - Report.LogCodedWarning (0, Report.WarningUnexpectedPackageChildNode, elem.Name.ToString ()); - break; - } - - if (gen == null) - continue; - int idx = name.IndexOf ('<'); - if (idx > 0) - name = name.Substring (0, idx); - by_name [name] = gen; - if (name.IndexOf ('.') > 0) - nested [name] = gen; - else - result.Add (gen); - } - - foreach (string name in nested.Keys) { - string top_ancestor = name.Substring (0, name.IndexOf ('.')); - if (by_name.ContainsKey (top_ancestor)) - by_name [top_ancestor].AddNestedType (nested [name]); - else { - Report.LogCodedWarning (0, Report.WarningNestedTypeAncestorNotFound, top_ancestor, nested [name].FullName); - nested [name].Invalidate (); - } - } - return result; - } - } -} diff --git a/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs b/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs index e92eb0b0b..fc7a94b86 100644 --- a/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs +++ b/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Java.Interop.Tools.Generator; using MonoDroid.Generation; using Xamarin.SourceWriter; diff --git a/tools/generator/SourceWriters/InterfaceMemberAlternativeClass.cs b/tools/generator/SourceWriters/InterfaceMemberAlternativeClass.cs index 2dddb1674..a427529d0 100644 --- a/tools/generator/SourceWriters/InterfaceMemberAlternativeClass.cs +++ b/tools/generator/SourceWriters/InterfaceMemberAlternativeClass.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Java.Interop.Tools.Generator; using MonoDroid.Generation; using Xamarin.SourceWriter; From 822d2e7c618fa186d3dac45724387425e9504c30 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Thu, 22 Apr 2021 16:04:44 -0500 Subject: [PATCH 2/2] Address review feedback. --- src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs | 3 ++- .../Metadata/FixupXmlDocument.cs | 2 +- .../Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs b/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs index 6e7b36a52..2c6c2b735 100644 --- a/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs +++ b/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Xml.Linq; using System.Xml.XPath; @@ -16,7 +17,7 @@ static class XmlExtensions { var value = element.XGetAttribute (name); - if (int.TryParse (value, out var result)) + if (int.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) return result; return null; diff --git a/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs b/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs index c3c39bc10..0578fd258 100644 --- a/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs +++ b/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs @@ -78,7 +78,7 @@ public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int produc // BG4302 Report.LogCodedError (Report.ErrorAddNodeInvalidXPath, e, metaitem, path); } - break; + break; case "change-node": try { var nodes = apiDocument.ApiDocument.XPathSelectElements (path); diff --git a/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs b/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs index 317e6a282..2a3238eb9 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs @@ -35,8 +35,9 @@ public static List Parse (XDocument doc, CodeGenerationOptions options) gens.AddRange (ParsePackage (elem, options)); break; case "enum": - var sym = new EnumSymbol (elem.XGetAttribute ("name")); - options.SymbolTable.AddType (elem.XGetAttribute ("name"), sym); + var name = elem.XGetAttribute ("name"); + var sym = new EnumSymbol (name); + options.SymbolTable.AddType (name, sym); continue; default: Report.LogCodedWarning (0, Report.WarningUnexpectedRootChildNode, elem.Name.ToString ());