diff --git a/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs b/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs index 0578fd258..96b4bcfa4 100644 --- a/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs +++ b/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs @@ -58,9 +58,9 @@ public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int produc else // BG8A00 Report.LogCodedWarning (0, Report.WarningRemoveNodeMatchedNoNodes, null, metaitem, $""); - } catch (XPathException e) { + } catch (XPathException) { // BG4301 - Report.LogCodedError (Report.ErrorRemoveNodeInvalidXPath, e, metaitem, path); + Report.LogCodedError (Report.ErrorRemoveNodeInvalidXPath, metaitem, path); } break; case "add-node": @@ -74,9 +74,9 @@ public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int produc foreach (var node in nodes) node.Add (metaitem.Nodes ()); } - } catch (XPathException e) { + } catch (XPathException) { // BG4302 - Report.LogCodedError (Report.ErrorAddNodeInvalidXPath, e, metaitem, path); + Report.LogCodedError (Report.ErrorAddNodeInvalidXPath, metaitem, path); } break; case "change-node": @@ -95,9 +95,9 @@ public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int produc if (!matched) // BG8A03 Report.LogCodedWarning (0, Report.WarningChangeNodeTypeMatchedNoNodes, null, metaitem, $""); - } catch (XPathException e) { + } catch (XPathException) { // BG4303 - Report.LogCodedError (Report.ErrorChangeNodeInvalidXPath, e, metaitem, path); + Report.LogCodedError (Report.ErrorChangeNodeInvalidXPath, metaitem, path); } break; case "attr": @@ -106,7 +106,7 @@ public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int produc if (string.IsNullOrEmpty (attr_name)) // BG4307 - Report.LogCodedError (Report.ErrorMissingAttrName, null, metaitem, path); + Report.LogCodedError (Report.ErrorMissingAttrName, metaitem, path); var nodes = attr_last_cache != null ? new XElement [] { attr_last_cache } : apiDocument.ApiDocument.XPathSelectElements (path); var attr_matched = 0; @@ -119,9 +119,9 @@ public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int produc Report.LogCodedWarning (0, Report.WarningAttrMatchedNoNodes, null, metaitem, $""); if (attr_matched != 1) attr_last_cache = null; - } catch (XPathException e) { + } catch (XPathException) { // BG4304 - Report.LogCodedError (Report.ErrorAttrInvalidXPath, e, metaitem, path); + Report.LogCodedError (Report.ErrorAttrInvalidXPath, metaitem, path); } break; case "move-node": @@ -140,9 +140,9 @@ public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int produc if (!matched) // BG8A05 Report.LogCodedWarning (0, Report.WarningMoveNodeMatchedNoNodes, null, metaitem, $""); - } catch (XPathException e) { + } catch (XPathException) { // BG4305 - Report.LogCodedError (Report.ErrorMoveNodeInvalidXPath, e, metaitem, path); + Report.LogCodedError (Report.ErrorMoveNodeInvalidXPath, metaitem, path); } break; case "remove-attr": @@ -159,9 +159,9 @@ public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int produc if (!matched) // BG8A06 Report.LogCodedWarning (0, Report.WarningRemoveAttrMatchedNoNodes, null, metaitem, $""); - } catch (XPathException e) { + } catch (XPathException) { // BG4306 - Report.LogCodedError (Report.ErrorRemoveAttrInvalidXPath, e, metaitem, path); + Report.LogCodedError (Report.ErrorRemoveAttrInvalidXPath, metaitem, path); } break; } diff --git a/src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs b/src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs index 1bd333165..42f6a4f1b 100644 --- a/src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs +++ b/src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs @@ -40,7 +40,7 @@ public void ApplyFixupFile (FixupXmlDocument fixup) fixup.Apply (this, ApiLevel, ProductVersion); } catch (XmlException ex) { // BG4200 - Report.LogCodedError (Report.ErrorFailedToProcessMetadata, ex.Message); + Report.LogCodedErrorAndExit (Report.ErrorFailedToProcessMetadata, null, fixup.FixupDocument, ex.Message); } } } diff --git a/src/Java.Interop.Tools.Generator/Utilities/Report.cs b/src/Java.Interop.Tools.Generator/Utilities/Report.cs index e216a1535..c8582d135 100644 --- a/src/Java.Interop.Tools.Generator/Utilities/Report.cs +++ b/src/Java.Interop.Tools.Generator/Utilities/Report.cs @@ -69,23 +69,30 @@ public LocalizedMessage (int code, string value) 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 LogCodedErrorAndExit (LocalizedMessage message, params string [] args) + => LogCodedErrorAndExit (message, null, null, args); - public static void LogCodedError (LocalizedMessage message, Exception? innerException, params string [] args) - => LogCodedError (message, innerException, null, -1, -1, args); + public static void LogCodedErrorAndExit (LocalizedMessage message, Exception? innerException, params string [] args) + => LogCodedErrorAndExit (message, innerException, null, args); - public static void LogCodedError (LocalizedMessage message, Exception? innerException, XNode node, params string? [] args) + public static void LogCodedErrorAndExit (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; + LogCodedError (message, node, args); - LogCodedError (message, innerException, file, line_info?.LineNumber ?? -1, line_info?.LinePosition ?? -1, args); + // Throwing a BindingGeneratorException will cause generator to terminate + throw new BindingGeneratorException (message.Code, string.Format (message.Value, args), innerException); } - public static void LogCodedError (LocalizedMessage message, Exception? innerException, string? sourceFile, int line, int column, params string? [] args) + public static void LogCodedError (LocalizedMessage message, XNode? node, params string? [] args) { - throw new BindingGeneratorException (message.Code, sourceFile, line, column, string.Format (message.Value, args), innerException); + var (file, line, col) = GetLineInfo (node); + + LogCodedError (message, file, line, col, args); + } + + public static void LogCodedError (LocalizedMessage message, string? sourceFile, int line, int column, params string? [] args) + { + Console.Error.WriteLine (Format (true, message.Code, sourceFile, line, column, message.Value, args)); } public static void LogCodedWarning (int verbosity, LocalizedMessage message, params string? [] args) @@ -99,10 +106,9 @@ public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exc 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; + var (file, line, col) = GetLineInfo (node); - LogCodedWarning (verbosity, message, innerException, file, line_info?.LineNumber ?? -1, line_info?.LinePosition ?? -1, args); + LogCodedWarning (verbosity, message, innerException, file, line, col, args); } public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exception? innerException, string? sourceFile, int line, int column, params string? [] args) @@ -145,12 +151,26 @@ public static string Format (bool error, int errorCode, string? sourceFile, int return ret + ": "; if (column > 0) - return ret + $"({line}, {column}): "; + return ret + $"({line},{column}): "; return ret + $"({line}): "; } + + static (string? file, int line, int col) GetLineInfo (XNode? node) + { + if (node is null) + return (null, -1, -1); + + var file = Uri.TryCreate (node.BaseUri, UriKind.Absolute, out var uri) ? uri.LocalPath : null; + var pos = (node as IXmlLineInfo)?.HasLineInfo () == true ? node as IXmlLineInfo : null; + + return (file, pos?.LineNumber ?? -1, pos?.LinePosition ?? -1); + } } - + + /// + /// Throwing this exception will cause generator to exit gracefully. + /// public class BindingGeneratorException : Exception { public BindingGeneratorException (int errorCode, string message) diff --git a/tests/generator-Tests/Unit-Tests/ReportTests.cs b/tests/generator-Tests/Unit-Tests/ReportTests.cs index cdb4925df..65a73e3ad 100644 --- a/tests/generator-Tests/Unit-Tests/ReportTests.cs +++ b/tests/generator-Tests/Unit-Tests/ReportTests.cs @@ -24,8 +24,8 @@ public void FormatTests () Assert.AreEqual ("error BG0037: There was a bad error", Report.Format (true, code, null, 0, 0, msg, args)); Assert.AreEqual (@"C:\code\test.cs: error BG0037: There was a bad error", Report.Format (true, code, sourcefile, 0, 0, msg, args)); Assert.AreEqual (@"C:\code\test.cs(32): error BG0037: There was a bad error", Report.Format (true, code, sourcefile, line, 0, msg, args)); - Assert.AreEqual (@"C:\code\test.cs(32, 12): error BG0037: There was a bad error", Report.Format (true, code, sourcefile, line, col, msg, args)); - Assert.AreEqual (@"C:\code\test.cs(32, 12): warning BG0037: There was a bad error", Report.Format (false, code, sourcefile, line, col, msg, args)); + Assert.AreEqual (@"C:\code\test.cs(32,12): error BG0037: There was a bad error", Report.Format (true, code, sourcefile, line, col, msg, args)); + Assert.AreEqual (@"C:\code\test.cs(32,12): warning BG0037: There was a bad error", Report.Format (false, code, sourcefile, line, col, msg, args)); } } } diff --git a/tools/generator/CodeGenerationOptions.cs b/tools/generator/CodeGenerationOptions.cs index 515b3585d..e483cf0a1 100644 --- a/tools/generator/CodeGenerationOptions.cs +++ b/tools/generator/CodeGenerationOptions.cs @@ -222,7 +222,7 @@ public string GetOutputName (string type) if (type.StartsWith ("params ")) return "params " + GetOutputName (type.Substring ("params ".Length)); if (type.StartsWith ("global::")) - Report.LogCodedError (Report.ErrorUnexpectedGlobal); + Report.LogCodedErrorAndExit (Report.ErrorUnexpectedGlobal); if (!UseGlobal) return type; diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index 2f8fc1cc8..b79ea12b5 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -22,11 +22,19 @@ public class CodeGenerator { public static int Main (string[] args) { - var options = CodeGeneratorOptions.Parse (args); - if (options == null) + try { + var options = CodeGeneratorOptions.Parse (args); + if (options == null) + return 1; + + Run (options); + } catch (BindingGeneratorException) { return 1; + } catch (Exception ex) { + Console.Error.WriteLine (Report.Format (true, 0, null, -1, -1, ex.ToString ())); + return 1; + } - Run (options); return 0; } diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiFixup.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiFixup.cs deleted file mode 100644 index f9500d368..000000000 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiFixup.cs +++ /dev/null @@ -1,198 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using System.Xml.XPath; -using System.Xml.Linq; - -using Xamarin.Android.Tools; -using Java.Interop.Tools.Generator; - -namespace MonoDroid.Generation -{ - public class ApiFixup - { - XDocument api_doc; - string apiSource = ""; - - public string ApiSource { get { return apiSource; } } - - public ApiFixup (XDocument apiDoc) - { - api_doc = apiDoc; - var api = api_doc.Root; - if (api != null) - apiSource = api.XGetAttribute ("api-source"); - } - - public void Process (IEnumerable metaDocs, string apiLevel, int productVersion) - { - foreach (var metaDoc in metaDocs) - Process (metaDoc, apiLevel, productVersion); - } - - bool ShouldSkip (XElement node, int apiLevel, int productVersion) - { - if (apiLevel > 0) { - 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"); - if (!string.IsNullOrEmpty (product_version) && int.Parse (product_version) > productVersion) - return true; - } - return false; - } - - bool ShouldApply (XElement node) - { - if (!string.IsNullOrEmpty (apiSource)) { - var targetsource = node.XGetAttribute ("api-source"); - if (string.IsNullOrEmpty (targetsource)) - return true; - return targetsource == apiSource; - } - return true; - } - - void Process (XDocument meta_doc, string apiLevelString, int productVersion) - { - int apiLevel = 0; - int.TryParse (apiLevelString, out apiLevel); - - var metadataChildren = meta_doc.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)) - continue; - string 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 = api_doc.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 = api_doc.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 = api_doc.XPathSelectElements (path); - bool 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 { - string 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 } : api_doc.XPathSelectElements (path); - int 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 { - string parent = metaitem.Value; - var parents = api_doc.XPathSelectElements (parent); - bool 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 { - string name = metaitem.XGetAttribute ("name"); - var nodes = api_doc.XPathSelectElements (path); - bool 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; - } - } - } - } -} - diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs index 43d6f6513..c0bb534b7 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs @@ -66,7 +66,7 @@ void RemoveOldConstants (StreamWriter sw) sw.WriteLine (" ", package, type, member, enu.StartsWith ("I:") ? "interface" : "class"); } catch (Exception ex) { - Report.LogCodedError (Report.ErrorFailedToRemoveConstants, ex, enu); + Report.LogCodedErrorAndExit (Report.ErrorFailedToRemoveConstants, ex, enu); throw; } } @@ -93,7 +93,7 @@ void FixOldConstants (StreamWriter sw) sw.WriteLine (" ", package, type, member, enu.StartsWith ("I:") ? "interface" : "class"); } catch (Exception ex) { - Report.LogCodedError (Report.ErrorFailedToRemoveConstants, ex, enu); + Report.LogCodedErrorAndExit (Report.ErrorFailedToRemoveConstants, ex, enu); throw; } } diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs index 677e174ba..be84e6949 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs @@ -222,7 +222,7 @@ internal List ParseMethodMappings (TextReader source, int filter_v try { list.Add (new ApiTransform (preserveTypeMode, items)); } catch (Exception ex) { - Report.LogCodedError (Report.ErrorFailedToProcessEnumMap, ex, s); + Report.LogCodedErrorAndExit (Report.ErrorFailedToProcessEnumMap, ex, s); throw; } }