From 1bc6dadf1032246cb40661805499c04d441f350e Mon Sep 17 00:00:00 2001
From: Tom Finley <tfinley@microsoft.com>
Date: Wed, 13 Jun 2018 15:01:01 -0700
Subject: [PATCH 1/2] Use HideEnumValueAttribute for both manifest and C# API
 generation.

---
 src/Microsoft.ML/CSharpApi.cs                 | 19 +++---------
 .../JsonUtils/JsonManifestUtils.cs            |  2 +-
 .../Internal/Tools/CSharpApiGenerator.cs      |  3 ++
 .../Internal/Tools/CSharpGeneratorUtils.cs    | 17 +++++++++--
 .../Common/EntryPoints/core_manifest.json     | 30 +++----------------
 5 files changed, 27 insertions(+), 44 deletions(-)

diff --git a/src/Microsoft.ML/CSharpApi.cs b/src/Microsoft.ML/CSharpApi.cs
index e943e76bca..75e06f0b98 100644
--- a/src/Microsoft.ML/CSharpApi.cs
+++ b/src/Microsoft.ML/CSharpApi.cs
@@ -11058,14 +11058,10 @@ namespace Transforms
     {
         public enum NAHandleTransformReplacementKind
         {
-            Default = 0,
-            Def = 0,
             DefaultValue = 0,
             Mean = 1,
             Minimum = 2,
-            Min = 2,
-            Maximum = 3,
-            Max = 3
+            Maximum = 3
         }
 
 
@@ -11153,7 +11149,7 @@ public void AddColumn(string outputColumn, string inputColumn)
             /// <summary>
             /// The replacement method to utilize
             /// </summary>
-            public NAHandleTransformReplacementKind ReplaceWith { get; set; } = NAHandleTransformReplacementKind.Def;
+            public NAHandleTransformReplacementKind ReplaceWith { get; set; } = NAHandleTransformReplacementKind.DefaultValue;
 
             /// <summary>
             /// Whether to impute values by slot
@@ -11527,17 +11523,10 @@ namespace Transforms
     {
         public enum NAReplaceTransformReplacementKind
         {
-            Default = 0,
             DefaultValue = 0,
-            Def = 0,
             Mean = 1,
-            Min = 2,
             Minimum = 2,
-            Max = 3,
-            Maximum = 3,
-            SpecifiedValue = 4,
-            Val = 4,
-            Value = 4
+            Maximum = 3
         }
 
 
@@ -11625,7 +11614,7 @@ public void AddColumn(string outputColumn, string inputColumn)
             /// <summary>
             /// The replacement method to utilize
             /// </summary>
-            public NAReplaceTransformReplacementKind ReplacementKind { get; set; } = NAReplaceTransformReplacementKind.Def;
+            public NAReplaceTransformReplacementKind ReplacementKind { get; set; } = NAReplaceTransformReplacementKind.DefaultValue;
 
             /// <summary>
             /// Whether to impute values by slot
diff --git a/src/Microsoft.ML/Runtime/EntryPoints/JsonUtils/JsonManifestUtils.cs b/src/Microsoft.ML/Runtime/EntryPoints/JsonUtils/JsonManifestUtils.cs
index 7950975a22..fd76ad8565 100644
--- a/src/Microsoft.ML/Runtime/EntryPoints/JsonUtils/JsonManifestUtils.cs
+++ b/src/Microsoft.ML/Runtime/EntryPoints/JsonUtils/JsonManifestUtils.cs
@@ -344,7 +344,7 @@ private static JToken BuildTypeToken(IExceptionContext ectx, FieldInfo fieldInfo
                 case TlcModule.DataKind.Enum:
                     jo = new JObject();
                     jo[FieldNames.Kind] = typeEnum.ToString();
-                    var values = Enum.GetNames(type);
+                    var values = Enum.GetNames(type).Where(n => type.GetField(n).GetCustomAttribute<HideEnumValueAttribute>() == null);
                     jo[FieldNames.Values] = new JArray(values);
                     return jo;
                 case TlcModule.DataKind.Array:
diff --git a/src/Microsoft.ML/Runtime/Internal/Tools/CSharpApiGenerator.cs b/src/Microsoft.ML/Runtime/Internal/Tools/CSharpApiGenerator.cs
index ad714a4998..db7c1d490d 100644
--- a/src/Microsoft.ML/Runtime/Internal/Tools/CSharpApiGenerator.cs
+++ b/src/Microsoft.ML/Runtime/Internal/Tools/CSharpApiGenerator.cs
@@ -6,6 +6,7 @@
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using System.Reflection;
 using Microsoft.ML.Runtime;
 using Microsoft.ML.Runtime.CommandLine;
 using Microsoft.ML.Runtime.Data;
@@ -156,6 +157,8 @@ private void GenerateEnums(IndentingTextWriter writer, Type inputType, string cu
                 for (int i = 0; i < names.Length; i++)
                 {
                     var name = names[i];
+                    if (type.GetField(name).GetCustomAttribute<HideEnumValueAttribute>() != null)
+                        continue;
                     var value = values.GetValue(i);
                     writer.WriteLine(prefix);
                     if (enumType == typeof(int))
diff --git a/src/Microsoft.ML/Runtime/Internal/Tools/CSharpGeneratorUtils.cs b/src/Microsoft.ML/Runtime/Internal/Tools/CSharpGeneratorUtils.cs
index fc9fabb758..cca73a21f9 100644
--- a/src/Microsoft.ML/Runtime/Internal/Tools/CSharpGeneratorUtils.cs
+++ b/src/Microsoft.ML/Runtime/Internal/Tools/CSharpGeneratorUtils.cs
@@ -6,6 +6,7 @@
 using System.CodeDom;
 using System.Collections.Generic;
 using System.Linq;
+using System.Reflection;
 using Microsoft.CSharp;
 using Microsoft.ML.Runtime.CommandLine;
 using Microsoft.ML.Runtime.EntryPoints;
@@ -279,10 +280,22 @@ public static string GetValue(ModuleCatalog catalog, Type fieldType, object fiel
                 case TlcModule.DataKind.Bool:
                     return (bool)fieldValue ? "true" : "false";
                 case TlcModule.DataKind.Enum:
+                    string enumAsString = fieldValue.ToString();
+                    if (fieldType.GetField(enumAsString).GetCustomAttribute<HideEnumValueAttribute>() != null)
+                    {
+                        // The default value for the enum has the hiding attribute on it. We will search for
+                        // alternate names. Regrettably I see no way beyond a manual scan.
+
+                        string unhiddenName = Enum.GetNames(fieldType).Zip(Enum.GetValues(fieldType).Cast<object>(), (name, val) => (name, val))
+                            .Where(pair => pair.val.Equals(fieldValue))
+                            .Where(pair => fieldType.GetField(pair.name).GetCustomAttribute<HideEnumValueAttribute>() == null)
+                            .Select(pair => pair.name).FirstOrDefault();
+                        enumAsString = unhiddenName ?? throw Contracts.Except($"Could not find unhidden alternative for '{fieldValue}' in type '{fieldType}'");
+                    }
                     if (generatedClasses.IsGenerated(fieldType.FullName))
-                        return generatedClasses.GetApiName(fieldType, rootNameSpace) + "." + fieldValue;
+                        return generatedClasses.GetApiName(fieldType, rootNameSpace) + "." + enumAsString;
                     else
-                        return generatedClasses.GetApiName(fieldType, "Runtime") + "." + fieldValue;
+                        return generatedClasses.GetApiName(fieldType, "Runtime") + "." + enumAsString;
                 case TlcModule.DataKind.Char:
                     return $"'{GetCharAsString((char)fieldValue)}'";
                 case TlcModule.DataKind.Component:
diff --git a/test/BaselineOutput/Common/EntryPoints/core_manifest.json b/test/BaselineOutput/Common/EntryPoints/core_manifest.json
index ea1a86a2e8..427b9c23b5 100644
--- a/test/BaselineOutput/Common/EntryPoints/core_manifest.json
+++ b/test/BaselineOutput/Common/EntryPoints/core_manifest.json
@@ -15390,14 +15390,10 @@
                   "Type": {
                     "Kind": "Enum",
                     "Values": [
-                      "Default",
-                      "Def",
                       "DefaultValue",
                       "Mean",
                       "Minimum",
-                      "Min",
-                      "Maximum",
-                      "Max"
+                      "Maximum"
                     ]
                   },
                   "Desc": "The replacement method to utilize",
@@ -15478,14 +15474,10 @@
           "Type": {
             "Kind": "Enum",
             "Values": [
-              "Default",
-              "Def",
               "DefaultValue",
               "Mean",
               "Minimum",
-              "Min",
-              "Maximum",
-              "Max"
+              "Maximum"
             ]
           },
           "Desc": "The replacement method to utilize",
@@ -15780,17 +15772,10 @@
                   "Type": {
                     "Kind": "Enum",
                     "Values": [
-                      "Default",
                       "DefaultValue",
-                      "Def",
                       "Mean",
-                      "Min",
                       "Minimum",
-                      "Max",
-                      "Maximum",
-                      "SpecifiedValue",
-                      "Val",
-                      "Value"
+                      "Maximum"
                     ]
                   },
                   "Desc": "The replacement method to utilize",
@@ -15856,17 +15841,10 @@
           "Type": {
             "Kind": "Enum",
             "Values": [
-              "Default",
               "DefaultValue",
-              "Def",
               "Mean",
-              "Min",
               "Minimum",
-              "Max",
-              "Maximum",
-              "SpecifiedValue",
-              "Val",
-              "Value"
+              "Maximum"
             ]
           },
           "Desc": "The replacement method to utilize",

From 7f94dd0d9c4b8c76b2ffc9e46144b55e11bf3fea Mon Sep 17 00:00:00 2001
From: Tom Finley <tfinley@microsoft.com>
Date: Fri, 15 Jun 2018 10:15:34 -0700
Subject: [PATCH 2/2] Unhide NAReplaceTransform.ReplacementKind.SpecifiedValue.

---
 src/Microsoft.ML.Transforms/NAReplaceTransform.cs         | 3 +--
 src/Microsoft.ML/CSharpApi.cs                             | 3 ++-
 test/BaselineOutput/Common/EntryPoints/core_manifest.json | 8 +++++---
 3 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/Microsoft.ML.Transforms/NAReplaceTransform.cs b/src/Microsoft.ML.Transforms/NAReplaceTransform.cs
index 522237e303..52989472fc 100644
--- a/src/Microsoft.ML.Transforms/NAReplaceTransform.cs
+++ b/src/Microsoft.ML.Transforms/NAReplaceTransform.cs
@@ -43,6 +43,7 @@ public enum ReplacementKind
             Mean,
             Minimum,
             Maximum,
+            SpecifiedValue,
 
             [HideEnumValue]
             Def = DefaultValue,
@@ -53,8 +54,6 @@ public enum ReplacementKind
             [HideEnumValue]
             Max = Maximum,
 
-            [HideEnumValue]
-            SpecifiedValue,
             [HideEnumValue]
             Val = SpecifiedValue,
             [HideEnumValue]
diff --git a/src/Microsoft.ML/CSharpApi.cs b/src/Microsoft.ML/CSharpApi.cs
index 75e06f0b98..05edec3cd9 100644
--- a/src/Microsoft.ML/CSharpApi.cs
+++ b/src/Microsoft.ML/CSharpApi.cs
@@ -11526,7 +11526,8 @@ public enum NAReplaceTransformReplacementKind
             DefaultValue = 0,
             Mean = 1,
             Minimum = 2,
-            Maximum = 3
+            Maximum = 3,
+            SpecifiedValue = 4
         }
 
 
diff --git a/test/BaselineOutput/Common/EntryPoints/core_manifest.json b/test/BaselineOutput/Common/EntryPoints/core_manifest.json
index 427b9c23b5..02cfd2c0c7 100644
--- a/test/BaselineOutput/Common/EntryPoints/core_manifest.json
+++ b/test/BaselineOutput/Common/EntryPoints/core_manifest.json
@@ -15775,7 +15775,8 @@
                       "DefaultValue",
                       "Mean",
                       "Minimum",
-                      "Maximum"
+                      "Maximum",
+                      "SpecifiedValue"
                     ]
                   },
                   "Desc": "The replacement method to utilize",
@@ -15844,7 +15845,8 @@
               "DefaultValue",
               "Mean",
               "Minimum",
-              "Maximum"
+              "Maximum",
+              "SpecifiedValue"
             ]
           },
           "Desc": "The replacement method to utilize",
@@ -15854,7 +15856,7 @@
           "Required": false,
           "SortOrder": 150.0,
           "IsNullable": false,
-          "Default": "Def"
+          "Default": "Default"
         },
         {
           "Name": "ImputeBySlot",