[corlib] TypeSpec.Parse for non-assembly qualified names.
authorAleksey Kliger <aleksey@xamarin.com>
Tue, 5 Apr 2016 22:18:37 +0000 (18:18 -0400)
committerAleksey Kliger <aleksey@xamarin.com>
Wed, 6 Apr 2016 17:56:09 +0000 (13:56 -0400)
Previously for types like "Foo[P,Q]" the recursive call of the parser
would incorrectly consume the delimiter after a type argument (ie the
',' or ']') which would leave the caller potentially past the end of the
string which would signal a failed parse.  New behavior is to peek at
the delimiter but leave it up to the caller to consume.

Also `Type.GetType(name, null, null)` should behave like
`Type.GetType(name)` (previously it dropped generic type arguments).

mcs/class/corlib/System/TypeSpec.cs

index 9ad485e07cd52b254e1265c18d95f3e0a2fc9c4d..3cf08ae352089a434b6c8ac006bf6ab5e9c6e1a3 100644 (file)
@@ -218,7 +218,7 @@ namespace System {
                        if (typeName == null)
                                throw new ArgumentNullException ("typeName");
 
-                       TypeSpec res = Parse (typeName, ref pos, false, false);
+                       TypeSpec res = Parse (typeName, ref pos, false, true);
                        if (pos < typeName.Length)
                                throw new ArgumentException ("Count not parse the whole type name", "typeName");
                        return res;
@@ -287,7 +287,7 @@ namespace System {
                {
                        Assembly asm = null;
                        if (assemblyResolver == null && typeResolver == null)
-                               return Type.GetType (name.DisplayName, throwOnError, ignoreCase);
+                               return Type.GetType (DisplayFullName, throwOnError, ignoreCase);
 
                        if (assembly_name != null) {
                                if (assemblyResolver != null)
@@ -376,6 +376,12 @@ namespace System {
                        pos = p;
                }
 
+               static void BoundCheck (int idx, string s)
+               {
+                       if (idx >= s.Length)
+                               throw new ArgumentException ("Invalid generic arguments spec", "typeName");
+               }
+
                static TypeIdentifier ParsedTypeIdentifier (string displayName)
                {
                        return TypeIdentifiers.FromDisplay(displayName);
@@ -383,6 +389,17 @@ namespace System {
 
                static TypeSpec Parse (string name, ref int p, bool is_recurse, bool allow_aqn)
                {
+                       // Invariants:
+                       //  - On exit p, is updated to pos the current unconsumed character.
+                       //
+                       //  - The callee peeks at but does not consume delimiters following
+                       //    recurisve parse (so for a recursive call like the args of "Foo[P,Q]"
+                       //    we'll return with p either on ',' or on ']'.  If the name was aqn'd
+                       //    "Foo[[P,assmblystuff],Q]" on return p with be on the ']' just
+                       //    after the "assmblystuff")
+                       //
+                       //  - If allow_aqn is True, assembly qualification is optional.
+                       //    If allow_aqn is False, assembly qualification is prohibited.
                        int pos = p;
                        int name_start;
                        bool in_modifiers = false;
@@ -450,18 +467,24 @@ namespace System {
                                                data.AddModifier (new PointerSpec(pointer_level));
                                                break;
                                        case ',':
-                                               if (is_recurse) {
+                                               if (is_recurse && allow_aqn) {
                                                        int end = pos;
                                                        while (end < name.Length && name [end] != ']')
                                                                ++end;
                                                        if (end >= name.Length)
                                                                throw new ArgumentException ("Unmatched ']' while parsing generic argument assembly name");
                                                        data.assembly_name = name.Substring (pos + 1, end - pos - 1).Trim ();
-                                                       p = end + 1;
+                                                       p = end;
                                                        return data;                                            
                                                }
-                                               data.assembly_name = name.Substring (pos + 1).Trim ();
-                                               pos = name.Length;
+                                               if (is_recurse) {
+                                                       p = pos;
+                                                       return data;
+                                               }
+                                               if (allow_aqn) {
+                                                       data.assembly_name = name.Substring (pos + 1).Trim ();
+                                                       pos = name.Length;
+                                               }
                                                break;
                                        case '[':
                                                if (data.is_byref)
@@ -482,11 +505,17 @@ namespace System {
                                                                if (aqn)
                                                                        ++pos; //skip '[' to the start of the type
                                                                args.Add (Parse (name, ref pos, true, aqn));
-                                                               if (pos >= name.Length)
-                                                                       throw new ArgumentException ("Invalid generic arguments spec", "typeName");
+                                                               BoundCheck (pos, name);
+                                                               if (aqn) {
+                                                                       if (name [pos] == ']')
+                                                                               ++pos;
+                                                                       else
+                                                                               throw new ArgumentException ("Unclosed assembly-qualified type name at " + name[pos], "typeName");
+                                                                       BoundCheck (pos, name);
+}
 
                                                                if (name [pos] == ']')
-                                                                               break;
+                                                                       break;
                                                                if (name [pos] == ',')
                                                                        ++pos; // skip ',' to the start of the next arg
                                                                else
@@ -523,7 +552,7 @@ namespace System {
                                                break;
                                        case ']':
                                                if (is_recurse) {
-                                                       p = pos + 1;
+                                                       p = pos;
                                                        return data;
                                                }
                                                throw new ArgumentException ("Unmatched ']'", "typeName");