diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/IdentifierValidator.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/IdentifierValidator.cs index d3158b19b..8f0039889 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/IdentifierValidator.cs +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/IdentifierValidator.cs @@ -41,6 +41,11 @@ public static string CreateValidIdentifier (string identifier, bool useEncodedRe return validIdentifier.Replace (normalizedIdentifier, "_"); } + public static bool IsValidIdentifier (string identifier) + { + return !validIdentifier.IsMatch (identifier); + } + // Makes uglier but unique identifiers by encoding each invalid character with its character value static string EncodeReplacement (Match match) => $"_x{(ushort) match.Value [0]}_"; } diff --git a/tools/generator/CodeGenerationOptions.cs b/tools/generator/CodeGenerationOptions.cs index 762d58268..b4aff1c43 100644 --- a/tools/generator/CodeGenerationOptions.cs +++ b/tools/generator/CodeGenerationOptions.cs @@ -3,7 +3,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Microsoft.CSharp; + +using Java.Interop.Tools.JavaCallableWrappers; + using Xamarin.Android.Binder; using Xamarin.AndroidTools.AnnotationSupport; @@ -97,21 +99,29 @@ public string GetOutputName (string s) return GetOutputName (s.Substring (0, idx)) + '<' + String.Join (", ", typeParams.ToArray ()) + '>'; } - CSharpCodeProvider code_provider = new CSharpCodeProvider (); - public string GetSafeIdentifier (string name) { + if (string.IsNullOrEmpty (name)) + return name; + // NOTE: "partial" differs in behavior on macOS vs. Windows, Windows reports "partial" as a valid identifier // This check ensures the same output on both platforms - if (name == "partial") - return name; + switch (name) { + case "partial": return name; + // `this` isn't in TypeNameUtilities.reserved_keywords; special-case. + case "this": return "this_"; + } // In the ideal world, it should not be applied twice. // Sadly that is not true in reality, so we need to exclude non-symbols // when replacing the argument name with a valid identifier. // (ReturnValue.ToNative() takes an argument which could be either an expression or mere symbol.) - if (name.LastOrDefault () != ')' && !name.Contains ('.')) - name = code_provider.IsValidIdentifier (name) ? name : name + '_'; + if (name [name.Length-1] != ')' && !name.Contains ('.') && !name.StartsWith ("@")) { + if (!IdentifierValidator.IsValidIdentifier (name) || + Array.BinarySearch (TypeNameUtilities.reserved_keywords, name) >= 0) { + name = name + "_"; + } + } return name.Replace ('$', '_'); } diff --git a/tools/generator/Utilities/TypeNameUtilities.cs b/tools/generator/Utilities/TypeNameUtilities.cs index 56a620f0a..465dca976 100644 --- a/tools/generator/Utilities/TypeNameUtilities.cs +++ b/tools/generator/Utilities/TypeNameUtilities.cs @@ -11,7 +11,7 @@ public static class TypeNameUtilities { // These must be sorted for BinarySearch to work // Missing "this" because it's handled elsewhere as "this_" - static string [] reserved_keywords = new [] { + internal static string [] reserved_keywords = new [] { "abstract", "as", "base", "bool", "break", "byte", "callback", "case", "catch", "char", "checked", "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", diff --git a/tools/generator/generator.csproj b/tools/generator/generator.csproj index b8f6ad969..237cb731a 100644 --- a/tools/generator/generator.csproj +++ b/tools/generator/generator.csproj @@ -1,7 +1,7 @@  - net472 + net472;netcoreapp3.1 Exe $(DefineConstants);GENERATOR;HAVE_CECIL;JCW_ONLY_TYPE_NAMES false