Unescape type names in the managed parser
authorRyan Lucia <rylucia@microsoft.com>
Tue, 17 Sep 2019 21:20:17 +0000 (17:20 -0400)
committerLarry Ewing <lewing@microsoft.com>
Mon, 7 Oct 2019 14:43:47 +0000 (09:43 -0500)
Commit migrated from https://github.com/mono/mono/commit/7c2d2a551cf831c2111b6070674b2f564d218efe

src/mono/netcore/System.Private.CoreLib/src/System/TypeNameParser.cs

index 0dff68d..a4f01a7 100644 (file)
@@ -167,7 +167,7 @@ namespace System
                        if (name.IndexOfAny (SPECIAL_CHARS) < 0)
                                return name;
 
-                       var sb = new StringBuilder ();
+                       var sb = new StringBuilder (name.Length);
                        foreach (char c in name) {
                                if (Array.IndexOf<char> (SPECIAL_CHARS, c) >= 0)
                                        sb.Append ('\\');
@@ -177,6 +177,21 @@ namespace System
                        return sb.ToString ();
                }
 
+               static string UnescapeTypeName (string name)
+               {
+                       if (name.IndexOfAny (SPECIAL_CHARS) < 0)
+                               return name;
+
+                       var sb = new StringBuilder (name.Length - 1);
+                       for (int i = 0; i < name.Length; ++i) {
+                               if (name [i] == '\\' && i + 1 < name.Length)
+                                       i++;
+                               sb.Append (name [i]);
+                       }
+
+                       return sb.ToString ();
+               }
+
                class ParsedName {
                        public List<string> Names;
                        public List<ParsedName> TypeArguments;
@@ -207,7 +222,10 @@ namespace System
                        */
                }
 
-               // Ported from the C version in mono_reflection_parse_type ()
+               // Ported from the C version in mono_reflection_parse_type_checked ()
+               // Entries to the Names list are unescaped to internal form while AssemblyName is not, in an effort to maintain
+               // consistency with our native parser. Since this function is just called recursively, that should also be true
+               // for ParsedNames in TypeArguments.
                static ParsedName ParseName (string name, bool recursed, int pos, out int end_pos)
                {
                        end_pos = 0;
@@ -223,7 +241,7 @@ namespace System
                        while (pos < name.Length) {
                                switch (name [pos]) {
                                case '+':
-                                       res.Names.Add (name.Substring (name_start, pos - name_start));
+                                       res.Names.Add (UnescapeTypeName (name.Substring (name_start, pos - name_start)));
                                        name_start = pos + 1;
                                        break;
                                case '\\':
@@ -244,7 +262,7 @@ namespace System
                                pos ++;
                        }
 
-                       res.Names.Add (name.Substring (name_start, pos - name_start));
+                       res.Names.Add (UnescapeTypeName (name.Substring (name_start, pos - name_start)));
 
                        bool isbyref = false;
                        bool isptr = false;