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;
{
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)
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);
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;
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)
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
break;
case ']':
if (is_recurse) {
- p = pos + 1;
+ p = pos;
return data;
}
throw new ArgumentException ("Unmatched ']'", "typeName");
} catch (ArgumentNullException) {}
}
- void MustAE (string tname) {
+ void MustAE_general (string tname, Func<string,Type> getType) {
try {
- var res = Type.GetType (tname, name => {
- return Assembly.Load (name);
- },(asm,name,ignore) => {
- return (object)asm == null ? Type.GetType (name, false, ignore) : asm.GetType (name, false, ignore);
- }, true, false);
+ var res = getType (tname);
Assert.Fail (tname);
} catch (ArgumentException) {}
}
+ void MustAE (string typename) {
+ MustAE_general (typename, tname => {
+ return Type.GetType (tname, name => {
+ return Assembly.Load (name);
+ },(asm,name,ignore) => {
+ return (object)asm == null ? Type.GetType (name, false, ignore) : asm.GetType (name, false, ignore);
+ }, true, false);
+ });
+ }
+
+ void MustAEnn (string typename) {
+ MustAE_general (typename, tname => Type.GetType (tname, null, null));
+ }
+
void MustFNFE (string tname) {
try {
var res = Type.GetType (tname, name => {
Assert.AreEqual (Type.GetType ("MonoTests.System.Foo`1[System.Int32"), null, "#15");
}
+ [Test]
+ public void GetTypeNullDelegatesParseGenericCorrectly () {
+ Assert.AreEqual (Type.GetType ("MonoTests.System.Foo`1", null, null), typeof (Foo<>), "#1");
+ Assert.AreEqual (Type.GetType ("MonoTests.System.Foo`1[System.Int32]", null, null), typeof (Foo<int>), "#2");
+ Assert.AreEqual (Type.GetType ("MonoTests.System.Foo`1[[System.Int32]]", null, null), typeof (Foo<int>), "#3");
+ Assert.AreEqual (Type.GetType ("MonoTests.System.Foo`1[System.Int32][]", null, null), typeof (Foo<int>[]), "#4");
+ Assert.AreEqual (Type.GetType ("MonoTests.System.Foo`1[System.Int32][,]", null, null), typeof (Foo<int>[,]), "#5");
+ Assert.AreEqual (Type.GetType ("MonoTests.System.Foo`1[]", null, null), typeof (Foo<>).MakeArrayType(), "#6");
+ Assert.AreEqual (Type.GetType ("MonoTests.System.Foo`1[,]", null, null), typeof (Foo<>).MakeArrayType (2), "#7");
+ Assert.AreEqual (Type.GetType ("MonoTests.System.Foo`1[][]", null, null), typeof (Foo<>).MakeArrayType ().MakeArrayType (), "#8");
+
+ MustAEnn ("MonoTests.System.Foo`1[][System.Int32]");
+ MustAEnn ("MonoTests.System.Foo`1[");
+ MustAEnn ("MonoTests.System.Foo`1[[");
+ MustAEnn ("MonoTests.System.Foo`1[[]");
+ MustAEnn ("MonoTests.System.Foo`1[,");
+ MustAEnn ("MonoTests.System.Foo`1[*");
+ MustAEnn ("MonoTests.System.Foo`1[System.Int32");
+ }
+
+ Dictionary<int, T> MakeDictHelper<T> (T[] arr) {
+ return new Dictionary<int, T>();
+ }
+
+ [Test]
+ public void GetTypeAnonymousParseCorrectly () {
+ var x = new { X = 1 };
+ var a = new [] { x };
+ var d = MakeDictHelper (a);
+
+ var x_type = x.GetType ();
+ var a_type = a.GetType ();
+ var d_type = d.GetType ();
+
+ Assert.AreEqual (Type.GetType (x_type.ToString ()), x_type, "#1");
+ Assert.AreEqual (Type.GetType (x_type.ToString (), null, null), x_type, "#2");
+ Assert.AreEqual (Type.GetType (a_type.ToString ()), a_type, "#3");
+ Assert.AreEqual (Type.GetType (a_type.ToString (), null, null), a_type, "#4");
+ Assert.AreEqual (Type.GetType (d_type.ToString ()), d_type, "#5");
+ Assert.AreEqual (Type.GetType (d_type.ToString (), null, null), d_type, "#6");
+
+ Assert.AreEqual (Type.GetType (x_type.FullName), x_type, "#7");
+ Assert.AreEqual (Type.GetType (x_type.FullName, null, null), x_type, "#8");
+ Assert.AreEqual (Type.GetType (a_type.FullName), a_type, "#9");
+ Assert.AreEqual (Type.GetType (a_type.FullName, null, null), a_type, "#10");
+ Assert.AreEqual (Type.GetType (d_type.FullName), d_type, "#11");
+ Assert.AreEqual (Type.GetType (d_type.FullName, null, null), d_type, "#12");
+
+ }
+
#if !MONOTOUCH && !MOBILE_STATIC
[Test]
[Category ("AndroidNotWorking")] // requires symbol writer
if (m->wrapper_type != MONO_WRAPPER_NONE)
return FALSE;
+ if (m == *dest) {
+ *dest = NULL;
+ return FALSE;
+ }
+
if (m->klass->image == mono_defaults.corlib && !strcmp (m->klass->name_space, "System.Reflection"))
return FALSE;
+ if (!(*dest)) {
+ *dest = m;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+get_caller_no_system_or_reflection (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
+{
+ MonoMethod **dest = (MonoMethod **)data;
+
+ /* skip unmanaged frames */
+ if (!managed)
+ return FALSE;
+
+ if (m->wrapper_type != MONO_WRAPPER_NONE)
+ return FALSE;
+
if (m == *dest) {
*dest = NULL;
return FALSE;
}
+
+ if (m->klass->image == mono_defaults.corlib && ((!strcmp (m->klass->name_space, "System.Reflection"))
+ || (!strcmp (m->klass->name_space, "System"))))
+ return FALSE;
+
if (!(*dest)) {
*dest = m;
return TRUE;
MonoType *type = NULL;
MonoAssembly *assembly = NULL;
gboolean type_resolve = FALSE;
+ MonoImage *rootimage = NULL;
mono_error_init (error);
m = mono_method_get_last_managed ();
dest = m;
- mono_stack_walk_no_il (get_caller_no_reflection, &dest);
+ /* Ugly hack: type_from_parsed_name is called from
+ * System.Type.internal_from_name, which is called most
+ * directly from System.Type.GetType(string,bool,bool) but
+ * also indirectly from places such as
+ * System.Type.GetType(string,func,func) (via
+ * System.TypeNameParser.GetType and System.TypeSpec.Resolve)
+ * so we need to skip over all of those to find the true caller.
+ *
+ * It would be nice if we had stack marks.
+ */
+ mono_stack_walk_no_il (get_caller_no_system_or_reflection, &dest);
if (!dest)
dest = m;
+
/*
* FIXME: mono_method_get_last_managed() sometimes returns NULL, thus
* causing ves_icall_System_Reflection_Assembly_GetCallingAssembly()
if (dest) {
assembly = dest->klass->image->assembly;
type_resolve = TRUE;
+ rootimage = assembly->image;
} else {
g_warning (G_STRLOC);
}
if (info->assembly.name)
assembly = mono_assembly_load (&info->assembly, assembly ? assembly->basedir : NULL, NULL);
-
if (assembly) {
/* When loading from the current assembly, AppDomain.TypeResolve will not be called yet */
- type = mono_reflection_get_type_checked (assembly->image, info, ignoreCase, &type_resolve, error);
+ type = mono_reflection_get_type_checked (rootimage, assembly->image, info, ignoreCase, &type_resolve, error);
return_val_if_nok (error, NULL);
}
+ // XXXX - aleksey -
+ // Say we're looking for System.Generic.Dict<int, Local>
+ // we FAIL the get type above, because S.G.Dict isn't in assembly->image. So we drop down here.
+ // but then we FAIL AGAIN because now we pass null as the image and the rootimage and everything
+ // is messed up when we go to construct the Local as the type arg...
+ //
+ // By contrast, if we started with Mine<System.Generic.Dict<int, Local>> we'd go in with assembly->image
+ // as the root and then even the detour into generics would still not screw us when we went to load Local.
if (!info->assembly.name && !type) {
/* try mscorlib */
- type = mono_reflection_get_type_checked (NULL, info, ignoreCase, &type_resolve, error);
+ type = mono_reflection_get_type_checked (rootimage, NULL, info, ignoreCase, &type_resolve, error);
return_val_if_nok (error, NULL);
}
if (assembly && !type && type_resolve) {
type_resolve = FALSE; /* This will invoke TypeResolve if not done in the first 'if' */
- type = mono_reflection_get_type_checked (assembly->image, info, ignoreCase, &type_resolve, error);
+ type = mono_reflection_get_type_checked (rootimage, assembly->image, info, ignoreCase, &type_resolve, error);
return_val_if_nok (error, NULL);
}
/* mono_reflection_parse_type() mangles the string */
if (!parsedOk) {
mono_reflection_free_type_info (&info);
- g_free (str);
if (throwOnError) {
- mono_set_pending_exception (mono_get_exception_argument("typeName", "failed parse"));
+ mono_error_init (&error);
+ mono_error_set_argument (&error, "typeName", "failed parse: %s", str);
+ mono_error_set_pending_exception (&error);
}
+ g_free (str);
return NULL;
}
if (module != NULL) {
if (module->image) {
- type = mono_reflection_get_type_checked (module->image, &info, ignoreCase, &type_resolve, &error);
+ type = mono_reflection_get_type_checked (module->image, module->image, &info, ignoreCase, &type_resolve, &error);
if (!is_ok (&error)) {
g_free (str);
mono_reflection_free_type_info (&info);
if (abuilder->modules) {
for (i = 0; i < mono_array_length (abuilder->modules); ++i) {
MonoReflectionModuleBuilder *mb = mono_array_get (abuilder->modules, MonoReflectionModuleBuilder*, i);
- type = mono_reflection_get_type_checked (&mb->dynamic_image->image, &info, ignoreCase, &type_resolve, &error);
+ type = mono_reflection_get_type_checked (&mb->dynamic_image->image, &mb->dynamic_image->image, &info, ignoreCase, &type_resolve, &error);
if (!is_ok (&error)) {
g_free (str);
mono_reflection_free_type_info (&info);
if (!type && abuilder->loaded_modules) {
for (i = 0; i < mono_array_length (abuilder->loaded_modules); ++i) {
MonoReflectionModule *mod = mono_array_get (abuilder->loaded_modules, MonoReflectionModule*, i);
- type = mono_reflection_get_type_checked (mod->image, &info, ignoreCase, &type_resolve, &error);
+ type = mono_reflection_get_type_checked (mod->image, mod->image, &info, ignoreCase, &type_resolve, &error);
if (!is_ok (&error)) {
g_free (str);
mono_reflection_free_type_info (&info);
}
}
else {
- type = mono_reflection_get_type_checked (assembly->assembly->image, &info, ignoreCase, &type_resolve, &error);
+ type = mono_reflection_get_type_checked (assembly->assembly->image, assembly->assembly->image, &info, ignoreCase, &type_resolve, &error);
if (!is_ok (&error)) {
g_free (str);
mono_reflection_free_type_info (&info);
#include <mono/utils/mono-error.h>
MonoType*
-mono_reflection_get_type_checked (MonoImage* image, MonoTypeNameParse *info, mono_bool ignorecase, mono_bool *type_resolve, MonoError *error);
+mono_reflection_get_type_checked (MonoImage *rootimage, MonoImage* image, MonoTypeNameParse *info, mono_bool ignorecase, mono_bool *type_resolve, MonoError *error);
MonoType*
mono_reflection_type_from_name_checked (char *name, MonoImage *image, MonoError *error);
/**
* mono_reflection_get_type_checked:
+ * @rootimage: the image of the currently active managed caller
* @image: a metadata context
* @info: type description structure
* @ignorecase: flag for case-insensitive string compares
*
*/
MonoType*
-mono_reflection_get_type_checked (MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase, gboolean *type_resolve, MonoError *error) {
+mono_reflection_get_type_checked (MonoImage *rootimage, MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase, gboolean *type_resolve, MonoError *error) {
mono_error_init (error);
- return mono_reflection_get_type_with_rootimage (image, image, info, ignorecase, type_resolve, error);
+ return mono_reflection_get_type_with_rootimage (rootimage, image, info, ignorecase, type_resolve, error);
}
MonoError error;
type_resolve = TRUE;
/* FIXME really okay to call while holding locks? */
- t = mono_reflection_get_type_checked (ass->image, &info, ignore_case, &type_resolve, &error);
+ t = mono_reflection_get_type_checked (ass->image, ass->image, &info, ignore_case, &type_resolve, &error);
mono_error_cleanup (&error);
if (t) {
g_ptr_array_add (res_classes, mono_type_get_class (t));
} else {
if (info.assembly.name)
NOT_IMPLEMENTED;
- t = mono_reflection_get_type_checked (ass->image, &info, ignorecase, &type_resolve, &error);
+ t = mono_reflection_get_type_checked (ass->image, ass->image, &info, ignorecase, &type_resolve, &error);
if (!is_ok (&error)) {
mono_error_cleanup (&error); /* FIXME don't swallow the error */
mono_reflection_free_type_info (&info);