diff --git a/src/utils/EnumMappings.Xml.cs b/src/utils/EnumMappings.Xml.cs index 975b498ad..dc13f361c 100644 --- a/src/utils/EnumMappings.Xml.cs +++ b/src/utils/EnumMappings.Xml.cs @@ -2,7 +2,8 @@ using System.IO; using System.Linq; using System.Xml; - +using System.Xml.Linq; +using System.Xml.XPath; using Xamarin.Android.Tools; namespace MonoDroid.Generation { @@ -23,19 +24,18 @@ internal static TextReader FieldXmlToCsv (string file) return null; var sw = new StringWriter (); - var doc = new XmlDocument (); - doc.Load (file); + var doc = XDocument.Load (file, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); - foreach (XmlElement e in doc.SelectNodes ("/enum-field-mappings/mapping")) { + foreach (var e in doc.XPathSelectElements ("/enum-field-mappings/mapping")) { string enu = GetMandatoryAttribute (e, "clr-enum-type"); - string jni_type = e.HasAttribute ("jni-class") + string jni_type = e.Attribute ("jni-class") != null ? e.XGetAttribute ("jni-class") - : e.HasAttribute ("jni-interface") + : e.Attribute ("jni-interface") != null ? "I:" + e.XGetAttribute ("jni-interface") : GetMandatoryAttribute (e, "jni-class or jni-interface"); - bool bitfield = e.HasAttribute ("bitfield") && e.XGetAttribute ("bitfield") == "true"; - foreach (XmlElement m in e.SelectNodes ("field")) { - string verstr = m.HasAttribute ("api-level") + bool bitfield = e.Attribute ("bitfield") != null && e.XGetAttribute ("bitfield") == "true"; + foreach (var m in e.XPathSelectElements ("field")) { + string verstr = m.Attribute ("api-level") != null ? m.XGetAttribute ("api-level") : "0"; string member = GetMandatoryAttribute (m, "clr-name"); @@ -48,10 +48,10 @@ internal static TextReader FieldXmlToCsv (string file) return new StringReader (sw.ToString ()); } - static string GetMandatoryAttribute (XmlElement e, string name) + static string GetMandatoryAttribute (XElement e, string name) { - if (!e.HasAttribute (name)) { - throw new InvalidOperationException (String.Format ("Mandatory attribute '{0}' is missing on a mapping element: {1}", name, e.OuterXml)); + if (e.Attribute (name) == null) { + throw new InvalidOperationException (String.Format ("Mandatory attribute '{0}' is missing on a mapping element: {1}", name, e.ToString ())); } return e.XGetAttribute (name); } diff --git a/src/utils/XmlExtensions.cs b/src/utils/XmlExtensions.cs index 4a1d1477b..6a8d4b2ef 100644 --- a/src/utils/XmlExtensions.cs +++ b/src/utils/XmlExtensions.cs @@ -2,16 +2,17 @@ using System.IO; using System.Linq; using System.Xml; +using System.Xml.Linq; using System.Xml.XPath; namespace Xamarin.Android.Tools { static class XmlExtensions { - public static string XGetAttribute (this XmlElement element, string name) + public static string XGetAttribute (this XElement element, string name) { - var attr = element.GetAttribute (name); - return attr != null ? attr.Trim () : null; + var attr = element.Attribute (name); + return attr != null ? attr.Value.Trim () : null; } public static string XGetAttribute (this XPathNavigator nav, string name, string ns) diff --git a/tools/generator/ApiFixup.cs b/tools/generator/ApiFixup.cs index 54081c572..c89c72752 100644 --- a/tools/generator/ApiFixup.cs +++ b/tools/generator/ApiFixup.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Xml; using System.Xml.XPath; +using System.Xml.Linq; using Xamarin.Android.Tools; @@ -10,47 +11,47 @@ namespace MonoDroid.Generation { public class ApiFixup { - XmlDocument api_doc; + XDocument api_doc; string apiSource = ""; public string ApiSource { get { return apiSource; } } - public ApiFixup (XmlDocument apiDoc) + public ApiFixup (XDocument apiDoc) { api_doc = apiDoc; - var api = api_doc.DocumentElement; + var api = api_doc.Root; if (api != null) apiSource = api.XGetAttribute ("api-source"); } - public void Process (IEnumerable metaDocs, string apiLevel, int productVersion) + public void Process (IEnumerable metaDocs, string apiLevel, int productVersion) { foreach (var metaDoc in metaDocs) Process (metaDoc, apiLevel, productVersion); } - bool ShouldSkip (XPathNavigator node, int apiLevel, int productVersion) + bool ShouldSkip (XElement node, int apiLevel, int productVersion) { if (apiLevel > 0) { - string apiSince = node.XGetAttribute ("api-since", ""); - string apiUntil = node.XGetAttribute ("api-until", ""); + string apiSince = node.XGetAttribute ("api-since"); + string apiUntil = node.XGetAttribute ("api-until"); if (!string.IsNullOrEmpty (apiSince) && int.Parse (apiSince) > apiLevel) return true; if (!string.IsNullOrEmpty (apiUntil) && int.Parse (apiUntil) < apiLevel) return true; } if (productVersion > 0) { - var product_version = node.XGetAttribute ("product-version", ""); + var product_version = node.XGetAttribute ("product-version"); if (!string.IsNullOrEmpty (product_version) && int.Parse (product_version) > productVersion) return true; } return false; } - bool ShouldApply (XPathNavigator node) + bool ShouldApply (XElement node) { if (!string.IsNullOrEmpty (apiSource)) { - var targetsource = node.XGetAttribute ("api-source", ""); + var targetsource = node.XGetAttribute ("api-source"); if (string.IsNullOrEmpty (targetsource)) return true; return targetsource == apiSource; @@ -58,158 +59,136 @@ bool ShouldApply (XPathNavigator node) return true; } - void Process (XmlDocument meta_doc, string apiLevelString, int productVersion) + void Process (XDocument meta_doc, string apiLevelString, int productVersion) { - XPathNavigator api_nav = api_doc.CreateNavigator (); - XPathNavigator meta_nav = meta_doc.CreateNavigator (); int apiLevel = 0; int.TryParse (apiLevelString, out apiLevel); - XPathNodeIterator metadata = meta_nav.Select ("/metadata/*"); + var metadataChildren = meta_doc.XPathSelectElements ("/metadata/*"); string prev_path = null; - XPathNavigator attr_last_cache = null; + XElement attr_last_cache = null; - while (metadata.MoveNext ()) { - var metanav = metadata.Current; - if (ShouldSkip (metanav, apiLevel, productVersion)) + foreach (var metaitem in metadataChildren) { + if (ShouldSkip (metaitem, apiLevel, productVersion)) continue; - if (!ShouldApply (metanav)) + if (!ShouldApply (metaitem)) continue; - string path = metanav.XGetAttribute ("path", ""); + string path = metaitem.XGetAttribute ("path"); if (path != prev_path) attr_last_cache = null; prev_path = path; - switch (metanav.LocalName) { + switch (metaitem.Name.LocalName) { case "remove-node": try { - XPathNodeIterator api_iter = api_nav.Select (path); - List matches = new List (); - while (api_iter.MoveNext ()) - matches.Add (((IHasXmlNode)api_iter.Current).GetNode () as XmlElement); - foreach (XmlElement api_node in matches) - api_node.ParentNode.RemoveChild (api_node); - if (matches.Count == 0) + var nodes = api_doc.XPathSelectElements (path).ToArray (); + if (nodes.Any ()) + foreach (var node in nodes) + node.Remove (); + else // BG8A00 - Report.Warning (0, Report.WarningApiFixup + 0, " matched no nodes.", path); + Report.Warning (0, Report.WarningApiFixup + 0, null, metaitem, " matched no nodes.", path); } catch (XPathException e) { // BG4A01 - Report.Error (Report.ErrorApiFixup + 1, e, "Invalid XPath specification: {0}", path); + Report.Error (Report.ErrorApiFixup + 1, e, metaitem, "Invalid XPath specification: {0}", path); } break; case "add-node": try { - XPathNodeIterator api_iter = api_nav.Select (path); + var nodes = api_doc.XPathSelectElements (path); bool matched = false; - while (api_iter.MoveNext ()) { - XmlElement api_node = ((IHasXmlNode)api_iter.Current).GetNode () as XmlElement; - foreach (XmlNode child in ((IHasXmlNode)metanav).GetNode().ChildNodes) - api_node.AppendChild (api_doc.ImportNode (child, true)); + if (!nodes.Any ()) + // BG8A01 + Report.Warning (0, Report.WarningApiFixup + 1, null, metaitem, " matched no nodes.", path); + else { + foreach (var node in nodes) + node.Add (metaitem.Nodes ()); matched = true; } - if (!matched) - // BG8A01 - Report.Warning (0, Report.WarningApiFixup + 1, " matched no nodes.", path); } catch (XPathException e) { // BG4A02 - Report.Error (Report.ErrorApiFixup + 2, e, "Invalid XPath specification: {0}", path); + Report.Error (Report.ErrorApiFixup + 2, e, metaitem, "Invalid XPath specification: {0}", path); } break; case "change-node": try { - XPathNodeIterator api_iter = api_nav.Select (path); + var nodes = api_doc.XPathSelectElements (path); bool matched = false; - while (api_iter.MoveNext ()) { - XmlElement node = ( (IHasXmlNode) api_iter.Current).GetNode () as XmlElement; - XmlElement parent = node.ParentNode as XmlElement; - XmlElement new_node = api_doc.CreateElement (metanav.Value); - - foreach (XmlNode child in node.ChildNodes) - new_node.AppendChild (child.Clone ()); - foreach (XmlAttribute attribute in node.Attributes) - new_node.Attributes.Append ( (XmlAttribute) attribute.Clone ()); - - parent.ReplaceChild (new_node, node); + 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.Warning (0, Report.WarningApiFixup + 3, " matched no nodes.", path); + Report.Warning (0, Report.WarningApiFixup + 3, null, metaitem, " matched no nodes.", path); } catch (XPathException e) { // BG4A03 - Report.Error (Report.ErrorApiFixup + 3, e, "Invalid XPath specification: {0}", path); + Report.Error (Report.ErrorApiFixup + 3, e, metaitem, "Invalid XPath specification: {0}", path); } break; case "attr": try { - string attr_name = metanav.XGetAttribute ("name", ""); + string attr_name = metaitem.XGetAttribute ("name"); if (string.IsNullOrEmpty (attr_name)) // BG4A07 - Report.Error (Report.ErrorApiFixup + 7, "Target attribute name is not specified for path: {0}", path); - var nodes = attr_last_cache != null ? - (IEnumerable) new XPathNavigator [] {attr_last_cache} : - api_nav.Select (path).OfType (); + Report.Error (Report.ErrorApiFixup + 7, null, metaitem, "Target attribute name is not specified for path: {0}", path); + var nodes = attr_last_cache != null ? new XElement [] { attr_last_cache } : api_doc.XPathSelectElements (path); int attr_matched = 0; foreach (var n in nodes) { - XmlElement node = ((IHasXmlNode) n).GetNode () as XmlElement; - node.SetAttribute (attr_name, metanav.Value); - //attr_last_cache = n; + n.SetAttributeValue (attr_name, metaitem.Value); attr_matched++; } if (attr_matched == 0) // BG8A04 - Report.Warning (0, Report.WarningApiFixup + 4, " matched no nodes.", path); + Report.Warning (0, Report.WarningApiFixup + 4, null, metaitem, " matched no nodes.", path); if (attr_matched != 1) attr_last_cache = null; } catch (XPathException e) { // BG4A04 - Report.Error (Report.ErrorApiFixup + 4, e, "Invalid XPath specification: {0}", path); + Report.Error (Report.ErrorApiFixup + 4, e, metaitem, "Invalid XPath specification: {0}", path); } break; case "move-node": try { - XPathExpression expr = api_nav.Compile (path); - string parent = metanav.Value; - XPathNodeIterator parent_iter = api_nav.Select (parent); + string parent = metaitem.Value; + var parents = api_doc.XPathSelectElements (parent); bool matched = false; - while (parent_iter.MoveNext ()) { - XmlNode parent_node = ((IHasXmlNode)parent_iter.Current).GetNode (); - XPathNodeIterator path_iter = parent_iter.Current.Clone ().Select (expr); - while (path_iter.MoveNext ()) { - XmlNode node = ((IHasXmlNode)path_iter.Current).GetNode (); - parent_node.AppendChild (node.Clone ()); - node.ParentNode.RemoveChild (node); - } + 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.Warning (0, Report.WarningApiFixup + 5, " matched no nodes.", path); + Report.Warning (0, Report.WarningApiFixup + 5, null, metaitem, " matched no nodes.", path); } catch (XPathException e) { // BG4A05 - Report.Error (Report.ErrorApiFixup + 5, e, "Invalid XPath specification: {0}", path); + Report.Error (Report.ErrorApiFixup + 5, e, metaitem, "Invalid XPath specification: {0}", path); } break; case "remove-attr": try { - string name = metanav.XGetAttribute ("name", ""); - XPathNodeIterator api_iter = api_nav.Select (path); + string name = metaitem.XGetAttribute ("name"); + var nodes = api_doc.XPathSelectElements (path); bool matched = false; - - while (api_iter.MoveNext ()) { - XmlElement node = ( (IHasXmlNode) api_iter.Current).GetNode () as XmlElement; - - node.RemoveAttribute (name); + + foreach (var node in nodes) { + node.RemoveAttributes (); matched = true; } if (!matched) // BG8A06 - Report.Warning (0, Report.WarningApiFixup + 6, " matched no nodes.", path); + Report.Warning (0, Report.WarningApiFixup + 6, null, metaitem, " matched no nodes.", path); } catch (XPathException e) { // BG4A06 - Report.Error (Report.ErrorApiFixup + 6, e, "Invalid XPath specification: {0}", path); + Report.Error (Report.ErrorApiFixup + 6, e, metaitem, "Invalid XPath specification: {0}", path); } break; } diff --git a/tools/generator/ClassGen.cs b/tools/generator/ClassGen.cs index d71f58949..3fc23fb09 100644 --- a/tools/generator/ClassGen.cs +++ b/tools/generator/ClassGen.cs @@ -12,6 +12,7 @@ using Xamarin.Android.Tools; using MonoDroid.Utils; +using System.Xml.Linq; namespace MonoDroid.Generation { #if USE_CECIL @@ -75,26 +76,23 @@ public class XmlClassGen : ClassGen { bool is_final; string base_type; - public XmlClassGen (XmlElement pkg, XmlElement elem) + public XmlClassGen (XElement pkg, XElement elem) : base (new XmlGenBaseSupport (pkg, elem))//FIXME: should not be xml specific { is_abstract = elem.XGetAttribute ("abstract") == "true"; is_final = elem.XGetAttribute ("final") == "true"; base_type = elem.XGetAttribute ("extends"); - foreach (XmlNode node in elem.ChildNodes) { - XmlElement child = node as XmlElement; - if (child == null) - continue; - switch (node.Name) { + foreach (var child in elem.Elements ()) { + switch (child.Name.LocalName) { case "implements": string iname = child.XGetAttribute ("name-generic-aware"); iname = iname.Length > 0 ? iname : child.XGetAttribute ("name"); AddInterface (iname); break; case "method": - var synthetic = child.GetAttribute ("synthetic") == "true"; - var finalizer = child.GetAttribute ("name") == "finalize" && - child.GetAttribute ("jni-signature") == "()V"; + var synthetic = child.XGetAttribute ("synthetic") == "true"; + var finalizer = child.XGetAttribute ("name") == "finalize" && + child.XGetAttribute ("jni-signature") == "()V"; if (!(synthetic || finalizer)) AddMethod (new XmlMethod (this, child)); break; @@ -107,7 +105,7 @@ public XmlClassGen (XmlElement pkg, XmlElement elem) case "typeParameters": break; // handled at GenBaseSupport default: - Report.Warning (0, Report.WarningClassGen + 1, "unexpected class child {0}.", node.Name); + Report.Warning (0, Report.WarningClassGen + 1, "unexpected class child {0}.", child.Name); break; } } diff --git a/tools/generator/Ctor.cs b/tools/generator/Ctor.cs index 8b5534499..092ef0d23 100644 --- a/tools/generator/Ctor.cs +++ b/tools/generator/Ctor.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Xml; +using System.Xml.Linq; using Mono.Cecil; using Xamarin.Android.Tools; @@ -60,7 +61,7 @@ public class XmlCtor : Ctor { bool missing_enclosing_class; string custom_attributes; - public XmlCtor (GenBase declaringType, XmlElement elem) : base (declaringType, new XmlMethodBaseSupport (elem)) + public XmlCtor (GenBase declaringType, XElement elem) : base (declaringType, new XmlMethodBaseSupport (elem)) { name = elem.XGetAttribute ("name"); int idx = name.LastIndexOf ('.'); @@ -69,11 +70,11 @@ public class XmlCtor : Ctor { // If 'elem' is a constructor for a non-static nested type, then // the type of the containing class must be inserted as the first // argument - nonStaticNestedType = idx > 0 && elem.ParentNode.Attributes ["static"].Value == "false"; + nonStaticNestedType = idx > 0 && elem.Parent.Attribute ("static").Value == "false"; if (nonStaticNestedType) { - string declName = elem.ParentNode.Attributes ["name"].Value; + string declName = elem.Parent.XGetAttribute ("name"); string expectedEnclosingName = declName.Substring (0, idx); - XmlElement enclosingType = GetPreviousClass (elem.ParentNode.PreviousSibling, expectedEnclosingName); + XElement enclosingType = GetPreviousClass (elem.Parent.PreviousNode, expectedEnclosingName); if (enclosingType == null) { missing_enclosing_class = true; Report.Warning (0, Report.WarningCtor + 0, "For {0}, could not find enclosing type '{1}'.", name, expectedEnclosingName); @@ -82,26 +83,27 @@ public class XmlCtor : Ctor { Parameters.AddFirst (Parameter.FromClassElement (enclosingType)); } - foreach (XmlNode child in elem.ChildNodes) { + foreach (var child in elem.Elements ()) { if (child.Name == "parameter") - Parameters.Add (Parameter.FromElement (child as XmlElement)); + Parameters.Add (Parameter.FromElement (child)); } - if (elem.HasAttribute ("customAttributes")) - custom_attributes = elem.GetAttribute ("customAttributes"); + if (elem.Attribute ("customAttributes") != null) + custom_attributes = elem.XGetAttribute ("customAttributes"); } - static XmlElement GetPreviousClass (XmlNode e, string nameValue) + static XElement GetPreviousClass (XNode n, string nameValue) { - while (e != null && - (e.NodeType != XmlNodeType.Element || - e.Name != "class" || - !e.Attributes ["name"].Value.StartsWith (nameValue) || - // this complicated check (instead of simple name string equivalence match) is required for nested class inside a generic class e.g. android.content.Loader.ForceLoadContentObserver. - (e.Attributes ["name"].Value != nameValue && e.Attributes ["name"].Value.IndexOf ('<') < 0))) { - e = e.PreviousSibling; + XElement e = null; + while (n != null && + ((e = n as XElement) == null || + e.Name != "class" || + !e.XGetAttribute ("name").StartsWith (nameValue, StringComparison.Ordinal) || + // this complicated check (instead of simple name string equivalence match) is required for nested class inside a generic class e.g. android.content.Loader.ForceLoadContentObserver. + (e.XGetAttribute ("name") != nameValue && e.XGetAttribute ("name").IndexOf ('<') < 0))) { + n = n.PreviousNode; } - return (XmlElement) e; + return (XElement) e; } public override bool IsNonStaticNestedType { diff --git a/tools/generator/EnumMappings.cs b/tools/generator/EnumMappings.cs index 25df0c699..026794f13 100644 --- a/tools/generator/EnumMappings.cs +++ b/tools/generator/EnumMappings.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; using Mono.Options; using Xamarin.Android.Tools; @@ -231,27 +233,26 @@ StringReader MethodXmlToCsv (string file) return null; var sw = new StringWriter (); - var doc = new XmlDocument (); - doc.Load (file); - foreach (XmlElement e in doc.SelectNodes ("/enum-method-mappings/mapping")) { + var doc = XDocument.Load (file, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + foreach (XElement e in doc.XPathSelectElements ("/enum-method-mappings/mapping")) { string version = e.XGetAttribute ("api-level"); string package = null; string java_class = null; - if (e.HasAttribute ("jni-class")) { + if (e.Attribute ("jni-class") != null) { string c = e.XGetAttribute ("jni-class"); int s = c.LastIndexOf ('/'); package = c.Substring (0, s).Replace ('/', '.'); java_class = c.Substring (s+1).Replace ('$', '.'); - } else if (e.HasAttribute ("jni-interface")) { + } else if (e.Attribute ("jni-interface") != null) { string c = e.XGetAttribute ("jni-interface"); int s = c.LastIndexOf ('/'); package = c.Substring (0, s).Replace ('/', '.'); java_class = "[Interface]" + c.Substring (s+1).Replace ('$', '.'); } else { - throw new InvalidOperationException (string.Format ("Missing mandatory attribute 'jni-class' or 'jni-interface' on a mapping element: {0}", e.OuterXml)); + throw new InvalidOperationException (string.Format ("Missing mandatory attribute 'jni-class' or 'jni-interface' on a mapping element: {0}", e)); } - foreach (XmlElement m in e.SelectNodes ("method")) { + foreach (var m in e.XPathSelectElements ("method")) { string method = GetMandatoryAttribute (m, "jni-name"); string parameter = GetMandatoryAttribute (m, "parameter"); string enum_type = GetMandatoryAttribute (m, "clr-enum-type"); diff --git a/tools/generator/Field.cs b/tools/generator/Field.cs index e1a7b644c..892ecea4c 100644 --- a/tools/generator/Field.cs +++ b/tools/generator/Field.cs @@ -8,6 +8,7 @@ using Xamarin.Android.Tools; using MonoDroid.Utils; +using System.Xml.Linq; namespace MonoDroid.Generation { #if USE_CECIL @@ -86,20 +87,20 @@ protected override Parameter SetterParameter { public class XmlField : Field { - XmlElement elem; + XElement elem; string java_name; string name; string enum_type; - public XmlField (XmlElement elem) + public XmlField (XElement elem) { this.elem = elem; java_name = elem.XGetAttribute ("name"); - if (elem.HasAttribute ("managedName")) + if (elem.Attribute ("managedName") != null) name = elem.XGetAttribute ("managedName"); else name = SymbolTable.StudlyCase (Char.IsLower (java_name [0]) || java_name.ToLower ().ToUpper () != java_name ? java_name : java_name.ToLower ()); - if (elem.HasAttribute ("enumType")) + if (elem.Attribute ("enumType") != null) enum_type = elem.XGetAttribute ("enumType"); } @@ -138,7 +139,7 @@ public override string TypeName { public override string Value { get { - string val = elem.GetAttribute ("value"); // do not trim + string val = elem.XGetAttribute ("value"); // do not trim if (!String.IsNullOrEmpty (val) && Symbol != null && Symbol.FullName == "char") val = "(char)" + val; return val; diff --git a/tools/generator/GenBaseSupport.cs b/tools/generator/GenBaseSupport.cs index 481d9f978..6af0841ee 100644 --- a/tools/generator/GenBaseSupport.cs +++ b/tools/generator/GenBaseSupport.cs @@ -8,6 +8,7 @@ using Xamarin.Android.Tools; using MonoDroid.Utils; +using System.Xml.Linq; namespace MonoDroid.Generation { @@ -155,7 +156,7 @@ public override string Visibility { public class XmlGenBaseSupport : GenBaseSupport { - public XmlGenBaseSupport (XmlElement pkg, XmlElement elem) + public XmlGenBaseSupport (XElement pkg, XElement elem) { deprecated = elem.XGetAttribute ("deprecated") != "not deprecated"; if (deprecated) { @@ -169,13 +170,13 @@ public XmlGenBaseSupport (XmlElement pkg, XmlElement elem) pkg_name = pkg.XGetAttribute ("name"); java_name = elem.XGetAttribute ("name"); - if (pkg.HasAttribute ("managedName")) { + if (pkg.Attribute ("managedName") != null) { ns = pkg.XGetAttribute ("managedName"); } else { ns = StringRocks.PackageToPascalCase (PackageName); } - var tpn = elem.SelectSingleNode ("typeParameters"); + var tpn = elem.Element ("typeParameters"); if (tpn != null) { type_params = GenericParameterDefinitionList.FromXml (tpn); is_generic = true; @@ -188,7 +189,7 @@ public XmlGenBaseSupport (XmlElement pkg, XmlElement elem) throw new NotSupportedException ("Looks like old API XML is used, which we don't support anymore."); } - if (elem.HasAttribute ("managedName")) { + if (elem.Attribute ("managedName") != null) { name = elem.XGetAttribute ("managedName"); full_name = String.Format ("{0}.{1}", ns, name); int idx = name.LastIndexOf ('.'); @@ -204,7 +205,7 @@ public XmlGenBaseSupport (XmlElement pkg, XmlElement elem) full_name = String.Format ("{0}.{1}{2}", ns, idx > 0 ? StringRocks.TypeToPascalCase (java_name.Substring (0, idx + 1)) : String.Empty, name); } - obfuscated = IsObfuscatedName (pkg.ChildNodes.Count, java_name) && elem.XGetAttribute ("obfuscated") != "false"; + obfuscated = IsObfuscatedName (pkg.Elements ().Count (), java_name) && elem.XGetAttribute ("obfuscated") != "false"; } public override bool IsAcw { @@ -325,7 +326,7 @@ bool IsObfuscatedName (int threshold, string name) public class InterfaceXmlGenBaseSupport : XmlGenBaseSupport { - public InterfaceXmlGenBaseSupport (XmlElement pkg, XmlElement elem) + public InterfaceXmlGenBaseSupport (XElement pkg, XElement elem) : base (pkg, elem) { } diff --git a/tools/generator/GenericParameterDefinition.cs b/tools/generator/GenericParameterDefinition.cs index 729b5034f..a64e22e42 100644 --- a/tools/generator/GenericParameterDefinition.cs +++ b/tools/generator/GenericParameterDefinition.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Text; using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; using Mono.Cecil; using Xamarin.Android.Tools; @@ -75,13 +77,13 @@ public static GenericParameterDefinitionList FromMetadata (IEnumerable (); - foreach (XmlElement x in n.SelectNodes ("genericConstraints/genericConstraint")) + foreach (var x in n.XPathSelectElements ("genericConstraints/genericConstraint")) csts.Add (x.XGetAttribute ("type")); ret.Add (new GenericParameterDefinition (n.XGetAttribute ("name"), csts.ToArray ())); } diff --git a/tools/generator/InterfaceGen.cs b/tools/generator/InterfaceGen.cs index e96d9a92c..f17c765e5 100644 --- a/tools/generator/InterfaceGen.cs +++ b/tools/generator/InterfaceGen.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Xml; +using System.Xml.Linq; using Mono.Cecil; using Xamarin.Android.Binder; @@ -39,24 +40,20 @@ public class XmlInterfaceGen : InterfaceGen { string args_type; - public XmlInterfaceGen (XmlElement pkg, XmlElement elem) + public XmlInterfaceGen (XElement pkg, XElement elem) : base (new InterfaceXmlGenBaseSupport (pkg, elem)) { - hasManagedName = elem.HasAttribute ("managedName"); + hasManagedName = elem.Attribute ("managedName") != null; args_type = elem.XGetAttribute ("argsType"); - foreach (XmlNode node in elem.ChildNodes) { - XmlElement child = node as XmlElement; - if (child == null) - continue; - - switch (node.Name) { + foreach (var child in elem.Elements ()) { + switch (child.Name.LocalName) { case "implements": string iname = child.XGetAttribute ("name-generic-aware"); iname = iname.Length > 0 ? iname : child.XGetAttribute ("name"); AddInterface (iname); break; case "method": - if (child.GetAttribute ("synthetic") != "true") + if (child.XGetAttribute ("synthetic") != "true") AddMethod (new XmlMethod (this, child)); break; case "field": @@ -65,7 +62,7 @@ public XmlInterfaceGen (XmlElement pkg, XmlElement elem) case "typeParameters": break; // handled at GenBaseSupport default: - Report.Warning (0, Report.WarningInterfaceGen + 0, "unexpected interface child {0}.", node.Name); + Report.Warning (0, Report.WarningInterfaceGen + 0, "unexpected interface child {0}.", child); break; } } diff --git a/tools/generator/Method.cs b/tools/generator/Method.cs index 6015477ad..08a1a4f25 100644 --- a/tools/generator/Method.cs +++ b/tools/generator/Method.cs @@ -9,6 +9,7 @@ using Xamarin.Android.Tools; using MonoDroid.Utils; +using System.Xml.Linq; namespace MonoDroid.Generation { #if USE_CECIL @@ -124,15 +125,15 @@ public override string CustomAttributes { public class XmlMethod : Method { - XmlElement elem; + XElement elem; - public XmlMethod (GenBase declaringType, XmlElement elem) + public XmlMethod (GenBase declaringType, XElement elem) : base (declaringType, new XmlMethodBaseSupport (elem)) { this.elem = elem; is_static = elem.XGetAttribute ("static") == "true"; is_virtual = !is_static && elem.XGetAttribute ("final") == "false"; - if (elem.HasAttribute ("managedName")) + if (elem.Attribute ("managedName") != null) name = elem.XGetAttribute ("managedName"); else name = StringRocks.MemberToPascalCase (JavaName); @@ -141,11 +142,11 @@ public XmlMethod (GenBase declaringType, XmlElement elem) if (declaringType is InterfaceGen) is_interface_default_method = !is_abstract && !is_static; - GenerateDispatchingSetter = elem.HasAttribute ("generateDispatchingSetter"); + GenerateDispatchingSetter = elem.Attribute ("generateDispatchingSetter") != null; - foreach (XmlNode child in elem.ChildNodes) { + foreach (var child in elem.Elements ()) { if (child.Name == "parameter") - Parameters.Add (Parameter.FromElement (child as XmlElement)); + Parameters.Add (Parameter.FromElement (child)); } FillReturnType (); } @@ -154,7 +155,7 @@ public XmlMethod (GenBase declaringType, XmlElement elem) public override string ArgsType { get { - var a = elem.Attributes ["argsType"]; + var a = elem.Attribute ("argsType"); if (a == null) return null; return a.Value; @@ -163,7 +164,7 @@ public override string ArgsType { public override string EventName { get { - var a = elem.Attributes ["eventName"]; + var a = elem.Attribute ("eventName"); if (a == null) return null; return a.Value; @@ -207,24 +208,19 @@ public override string Name { // FIXME: this should not require enumReturn. Somewhere in generator uses this property improperly. public override string Return { - get { return elem.HasAttribute ("enumReturn") ? elem.XGetAttribute ("enumReturn") : elem.XGetAttribute ("return"); } + get { return IsReturnEnumified ? elem.XGetAttribute ("enumReturn") : elem.XGetAttribute ("return"); } } public override string ManagedReturn { - get { return elem.HasAttribute ("enumReturn") ? elem.XGetAttribute ("enumReturn") : elem.XGetAttribute ("managedReturn"); } + get { return IsReturnEnumified ? elem.XGetAttribute ("enumReturn") : elem.XGetAttribute ("managedReturn"); } } public override bool IsReturnEnumified { - get { return elem.HasAttribute ("enumReturn"); } + get { return elem.Attribute ("enumReturn") != null; } } protected override string PropertyNameOverride { - get { - var pn = elem.Attributes ["propertyName"]; - if (pn == null) - return null; - return pn.Value; - } + get { return elem.XGetAttribute ("propertyName"); } } static readonly Regex ApiLevel = new Regex (@"api-(\d+).xml"); @@ -248,17 +244,12 @@ public override bool Asyncify { if (IsOverride) return false; - return elem.HasAttribute ("generateAsyncWrapper"); + return elem.Attribute ("generateAsyncWrapper") != null; } } public override string CustomAttributes { - get { - if (!elem.HasAttribute ("customAttributes")) - return null; - - return elem.GetAttribute ("customAttributes"); - } + get { return elem.XGetAttribute ("customAttributes"); } } } diff --git a/tools/generator/MethodBase.cs b/tools/generator/MethodBase.cs index ee47ae33c..251b91345 100644 --- a/tools/generator/MethodBase.cs +++ b/tools/generator/MethodBase.cs @@ -9,6 +9,7 @@ using Java.Interop.Tools.TypeNameMappings; using Xamarin.Android.Tools; +using System.Xml.Linq; namespace MonoDroid.Generation { @@ -82,17 +83,17 @@ public IEnumerable GetParameters (CustomAttribute regatt) public class XmlMethodBaseSupport : IMethodBaseSupport { - XmlElement elem; + XElement elem; GenericParameterDefinitionList generic_arguments; - public XmlMethodBaseSupport (XmlElement elem) + public XmlMethodBaseSupport (XElement elem) { this.elem = elem; - var tps = elem.SelectSingleNode ("typeParameters"); + var tps = elem.Element ("typeParameters"); generic_arguments = tps != null ? GenericParameterDefinitionList.FromXml (tps) : null; } - public XmlElement Element { + public XElement Element { get { return elem; } } diff --git a/tools/generator/Parameter.cs b/tools/generator/Parameter.cs index 8d89f5606..f113b9ef2 100644 --- a/tools/generator/Parameter.cs +++ b/tools/generator/Parameter.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Xml; +using System.Xml.Linq; using Mono.Cecil; using Xamarin.Android.Binder; @@ -261,25 +262,25 @@ public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList return true; } - public static Parameter FromElement (XmlElement elem) + public static Parameter FromElement (XElement elem) { string managedName = elem.XGetAttribute ("managedName"); string name = !string.IsNullOrEmpty (managedName) ? managedName : SymbolTable.MangleName (elem.XGetAttribute ("name")); string java_type = elem.XGetAttribute ("type"); - string enum_type = elem.HasAttribute ("enumType") ? elem.XGetAttribute ("enumType") : null; - string managed_type = elem.HasAttribute ("managedType") ? elem.XGetAttribute ("managedType") : null; + string enum_type = elem.Attribute ("enumType") != null ? elem.XGetAttribute ("enumType") : null; + string managed_type = elem.Attribute ("managedType") != null ? elem.XGetAttribute ("managedType") : null; // FIXME: "enum_type ?? java_type" should be extraneous. Somewhere in generator uses it improperly. var result = new Parameter (name, enum_type ?? java_type, enum_type ?? managed_type, enum_type != null, java_type); - if (elem.HasAttribute ("sender")) + if (elem.Attribute ("sender") != null) result.IsSender = true; return result; } - public static Parameter FromClassElement (XmlElement elem) + public static Parameter FromClassElement (XElement elem) { string name = "__self"; string java_type = elem.XGetAttribute ("name"); - string java_package = elem.ParentNode.Attributes ["name"].Value; + string java_package = elem.Parent.XGetAttribute ("name"); return new Parameter (name, java_package + "." + java_type, null, false); } diff --git a/tools/generator/Parser.cs b/tools/generator/Parser.cs index 40b3c3b6b..1e17fe598 100644 --- a/tools/generator/Parser.cs +++ b/tools/generator/Parser.cs @@ -3,7 +3,7 @@ using System.IO; using System.Linq; using System.Xml; - +using System.Xml.Linq; using Xamarin.Android.Tools; namespace MonoDroid.Generation { @@ -12,16 +12,15 @@ public class Parser { public string ApiSource { get; private set; } - public XmlDocument Load (string filename) + public XDocument Load (string filename) { - XmlDocument doc = new XmlDocument (); + XDocument doc = null; try { - doc.Load (filename); + doc = XDocument.Load (filename, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); } catch (XmlException e) { Report.Verbose (0, "Exception: {0}", e); Report.Warning (0, Report.WarningParser + 0, e, "Invalid XML file '{0}': {1}", filename, e.Message); - doc = null; } return doc; @@ -39,7 +38,7 @@ public List Parse (string filename, IEnumerable fixups, string } } - public List Parse (XmlDocument doc, IEnumerable fixups, string apiLevel, int productVersion) + public List Parse (XDocument doc, IEnumerable fixups, string apiLevel, int productVersion) { if (doc == null) return null; @@ -53,21 +52,17 @@ public List Parse (XmlDocument doc, IEnumerable fixups, string return null; } - XmlElement root = doc.DocumentElement; + var root = doc.Root; - if ((root == null) || !root.HasChildNodes) { + if ((root == null) || !root.HasElements) { Report.Warning (0, Report.WarningParser + 1, "No packages found."); return null; } List gens = new List (); - foreach (XmlNode child in root.ChildNodes) { - XmlElement elem = child as XmlElement; - if (elem == null) - continue; - - switch (child.Name) { + foreach (var elem in root.Elements ()) { + switch (elem.Name.LocalName) { case "package": gens.AddRange (ParsePackage (elem)); break; @@ -76,7 +71,7 @@ public List Parse (XmlDocument doc, IEnumerable fixups, string SymbolTable.AddType (elem.XGetAttribute ("name"), sym); continue; default: - Report.Warning (0, Report.WarningParser + 2, "Unexpected child node: {0}.", child.Name); + Report.Warning (0, Report.WarningParser + 2, "Unexpected child node: {0}.", elem.Name); break; } } @@ -84,26 +79,22 @@ public List Parse (XmlDocument doc, IEnumerable fixups, string return gens; } - List ParsePackage (XmlElement ns) + List ParsePackage (XElement ns) { return ParsePackage (ns, null); } - List ParsePackage (XmlElement ns, Predicate p) + List ParsePackage (XElement ns, Predicate p) { List result = new List (); Dictionary nested = new Dictionary (); Dictionary by_name = new Dictionary (); - foreach (XmlNode def in ns.ChildNodes) { - - XmlElement elem = def as XmlElement; - if (elem == null) - continue; + foreach (var elem in ns.Elements ()) { string name = elem.XGetAttribute ("name"); GenBase gen = null; - switch (def.Name) { + switch (elem.Name.LocalName) { case "class": if (elem.XGetAttribute ("obfuscated") == "true") continue; @@ -115,7 +106,7 @@ List ParsePackage (XmlElement ns, Predicate p) gen = new XmlInterfaceGen (ns, elem); break; default: - Report.Warning (0, Report.WarningParser + 3, "Unexpected node in package element: {0}.", def.Name); + Report.Warning (0, Report.WarningParser + 3, "Unexpected node in package element: {0}.", elem.Name); break; } diff --git a/tools/generator/Report.cs b/tools/generator/Report.cs index f3cce8d98..0db1bbd17 100644 --- a/tools/generator/Report.cs +++ b/tools/generator/Report.cs @@ -1,5 +1,8 @@ using System; using System.Linq; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; namespace MonoDroid.Generation { @@ -31,25 +34,63 @@ public class Report public static void Error (int errorCode, string format, params object[] args) { - Error (errorCode, null, format, args); + Error (errorCode, null, null, -1, -1, format, args); } - - public static void Error (int errorCode, Exception innerException, string format, params object[] args) + + public static void Error (int errorCode, string sourceFile, int line, int column, string format, params object [] args) { - throw new BindingGeneratorException (errorCode, string.Format (format, args), innerException); + Error (errorCode, null, sourceFile, line, column, format, args); + } + + public static void Error (int errorCode, Exception innerException, string format, params object [] args) + { + Error (errorCode, innerException, null, -1, -1, format, args); + } + + public static void Error (int errorCode, Exception innerException, XNode node, string format, params object [] args) + { + Uri uri; + string file = Uri.TryCreate (node.BaseUri, UriKind.Absolute, out uri) ? uri.LocalPath : null; + IXmlLineInfo li = node as IXmlLineInfo; + li = li != null && li.HasLineInfo () ? li : null; + Error (errorCode, innerException, file, li != null ? li.LineNumber : -1, li != null ? li.LinePosition : -1, format, args); + } + + public static void Error (int errorCode, Exception innerException, string sourceFile, int line, int column, string format, params object[] args) + { + throw new BindingGeneratorException (errorCode, sourceFile, line, column, string.Format (format, args), innerException); } public static void Warning (int verbosity, int errorCode, string format, params object[] args) { Warning (verbosity, errorCode, null, format, args); } + + public static void Warning (int verbosity, int errorCode, Exception innerException, XNode node, string format, params object [] args) + { + Uri uri; + string file = Uri.TryCreate (node.BaseUri, UriKind.Absolute, out uri) ? uri.LocalPath : null; + IXmlLineInfo li = node as IXmlLineInfo; + li = li != null && li.HasLineInfo () ? li : null; + Warning (verbosity, errorCode, innerException, file, li != null ? li.LineNumber : -1, li != null ? li.LinePosition : -1, format, args); + } + + public static void Warning (int verbosity, int errorCode, string sourceFile, int line, int column, string format, params object[] args) + { + Warning (verbosity, errorCode, null, sourceFile, line, column, format, args); + } + + public static void Warning (int verbosity, int errorCode, Exception innerException, string format, params object [] args) + { + Warning (verbosity, errorCode, innerException, null, -1, -1, format, args); + } - public static void Warning (int verbosity, int errorCode, Exception innerException, string format, params object[] args) + public static void Warning (int verbosity, int errorCode, Exception innerException, string sourceFile, int line, int column, string format, params object[] args) { if (verbosity > (Verbosity ?? 0)) return; string supp = innerException != null ? " For details, see verbose output." : null; - Console.Error.WriteLine (Format (false, errorCode, format, args) + supp); + Console.Error.WriteLine (Format (false, errorCode, sourceFile, line, column, format, args) + supp); if (innerException != null) Console.Error.WriteLine (innerException); } @@ -60,10 +101,16 @@ public static void Verbose (int verbosity, string format, params object[] args) return; Console.Error.WriteLine (format, args); } + + public static string Format (bool error, int errorCode, string format, params object [] args) + { + return Format (error, errorCode, null, -1, -1, format, args); + } - public static string Format (bool error, int errorCode, string format, params object[] args) + public static string Format (bool error, int errorCode, string sourceFile, int line, int column, string format, params object[] args) { - return string.Format ("{0}{1} BG{2:X04}: ", "" /* origin? */, error ? "error" : "warning", errorCode) + + var origin = sourceFile != null ? sourceFile + (line > 0 ? column > 0 ? $"({line}, {column})" : $"({line})" : null) + ' ' : null; + return string.Format ("{0}{1} BG{2:X04}: ", origin, error ? "error" : "warning", errorCode) + string.Format (format, args); } } @@ -75,7 +122,11 @@ public BindingGeneratorException (int errorCode, string message) { } public BindingGeneratorException (int errorCode, string message, Exception innerException) - : base (Report.Format (true, errorCode, message), innerException) + : this (errorCode, null, -1, -1, message, 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) { } }