Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,29 @@ public void GetTypeByName_ValidType_ReturnsExpected(string typeName, Type expect
Assert.Equal(expectedType, Type.GetType(typeName.ToLower(), throwOnError: false, ignoreCase: true));
}

public static IEnumerable<object[]> GetTypeByName_InvalidElementType()
{
Type expectedException = PlatformDetection.IsMonoRuntime
? typeof(ArgumentException) // https://github.com/dotnet/runtime/issues/45033
: typeof(TypeLoadException);

yield return new object[] { "System.Int32&&", expectedException, true };
yield return new object[] { "System.Int32&*", expectedException, true };
yield return new object[] { "System.Int32&[]", expectedException, true };
yield return new object[] { "System.Int32&[*]", expectedException, true };
yield return new object[] { "System.Int32&[,]", expectedException, true };

// https://github.com/dotnet/runtime/issues/45033
if (!PlatformDetection.IsMonoRuntime)
{
yield return new object[] { "..Outside`1", expectedException, false };
yield return new object[] { ".Outside`1+.Inside`1", expectedException, false };

yield return new object[] { "System.Void[]", expectedException, true };
yield return new object[] { "System.TypedReference[]", expectedException, true };
}
}

[Theory]
[InlineData("system.nullable`1[system.int32]", typeof(TypeLoadException), false)]
[InlineData("System.NonExistingType", typeof(TypeLoadException), false)]
Expand All @@ -517,15 +540,7 @@ public void GetTypeByName_ValidType_ReturnsExpected(string typeName, Type expect
[InlineData("Outside`2", typeof(TypeLoadException), false)]
[InlineData("Outside`1[System.Boolean, System.Int32]", typeof(ArgumentException), true)]
[InlineData(".System.Int32", typeof(TypeLoadException), false)]
[InlineData("..Outside`1", typeof(TypeLoadException), false)]
[InlineData(".Outside`1+.Inside`1", typeof(TypeLoadException), false)]
[InlineData("System.Int32&&", typeof(TypeLoadException), true)]
[InlineData("System.Int32&*", typeof(TypeLoadException), true)]
[InlineData("System.Int32&[]", typeof(TypeLoadException), true)]
[InlineData("System.Int32&[*]", typeof(TypeLoadException), true)]
[InlineData("System.Int32&[,]", typeof(TypeLoadException), true)]
[InlineData("System.Void[]", typeof(TypeLoadException), true)]
[InlineData("System.TypedReference[]", typeof(TypeLoadException), true)]
[MemberData(nameof(GetTypeByName_InvalidElementType))]
public void GetTypeByName_Invalid(string typeName, Type expectedException, bool alwaysThrowsException)
{
if (!alwaysThrowsException)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ internal unsafe ref partial struct TypeNameResolver
private Func<Assembly?, string, bool, Type?>? _typeResolver;
private bool _throwOnError;
private bool _ignoreCase;
private bool _extensibleParser;
private ref StackCrawlMark _stackMark;

[RequiresUnreferencedCode("The type might be removed")]
Expand All @@ -28,7 +27,6 @@ internal unsafe ref partial struct TypeNameResolver
Func<Assembly?, string, bool, Type?>? typeResolver,
bool throwOnError,
bool ignoreCase,
bool extensibleParser,
ref StackCrawlMark stackMark)
{
ArgumentNullException.ThrowIfNull(typeName);
Expand All @@ -54,7 +52,6 @@ internal unsafe ref partial struct TypeNameResolver
_typeResolver = typeResolver,
_throwOnError = throwOnError,
_ignoreCase = ignoreCase,
_extensibleParser = extensibleParser,
_stackMark = ref stackMark
}.Resolve(parsed);
}
Expand Down Expand Up @@ -144,16 +141,7 @@ internal unsafe ref partial struct TypeNameResolver
if (_ignoreCase)
bindingFlags |= BindingFlags.IgnoreCase;

if (type is RuntimeType rt)
{
// Compat: Non-extensible parser allows ambiguous matches with ignore case lookup
bool ignoreAmbiguousMatch = !_extensibleParser && _ignoreCase;
type = rt.GetNestedType(nestedTypeNames[i], bindingFlags, ignoreAmbiguousMatch);
}
else
{
type = type.GetNestedType(nestedTypeNames[i], bindingFlags);
}
type = type.GetNestedType(nestedTypeNames[i], bindingFlags);

if (type is null)
{
Expand Down
30 changes: 14 additions & 16 deletions src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs
Original file line number Diff line number Diff line change
Expand Up @@ -679,17 +679,21 @@ private ListBuilder<FieldInfo> GetFieldCandidates(string? name, BindingFlags bin
return candidates;
}

private ListBuilder<Type> GetNestedTypeCandidates(string? name, BindingFlags bindingAttr, bool allowPrefixLookup)
private ListBuilder<Type> GetNestedTypeCandidates(string? fullname, BindingFlags bindingAttr, bool allowPrefixLookup)
{
bool prefixLookup;
bindingAttr &= ~BindingFlags.Static;
FilterHelper(bindingAttr, ref name, allowPrefixLookup, out bool prefixLookup, out _, out MemberListType listType);
string? name, ns;
MemberListType listType;
SplitName(fullname, out name, out ns);
FilterHelper(bindingAttr, ref name, allowPrefixLookup, out prefixLookup, out _, out listType);

RuntimeType[] cache = GetNestedTypes_internal(name, bindingAttr, listType);
ListBuilder<Type> candidates = new ListBuilder<Type>(cache.Length);
for (int i = 0; i < cache.Length; i++)
{
RuntimeType nestedClass = cache[i];
if (FilterApplyType(nestedClass, bindingAttr, name, prefixLookup, null))
if (FilterApplyType(nestedClass, bindingAttr, name, prefixLookup, ns))
{
candidates.Add(nestedClass);
}
Expand Down Expand Up @@ -1000,39 +1004,33 @@ public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
}

[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
internal Type? GetNestedType([MaybeNull] string name, BindingFlags bindingAttr, bool ignoreAmbiguousMatch)
public override Type? GetNestedType(string fullname, BindingFlags bindingAttr)
{
ArgumentNullException.ThrowIfNull(name);
ArgumentNullException.ThrowIfNull(fullname);

bindingAttr &= ~BindingFlags.Static;
FilterHelper(bindingAttr, ref name, out _, out MemberListType listType);
string? name, ns;
MemberListType listType;
SplitName(fullname, out name, out ns);
FilterHelper(bindingAttr, ref name, out _, out listType);
RuntimeType[] cache = GetNestedTypes_internal(name, bindingAttr, listType);
RuntimeType? match = null;

for (int i = 0; i < cache.Length; i++)
{
RuntimeType nestedType = cache[i];
if (FilterApplyType(nestedType, bindingAttr, name, false, null))
if (FilterApplyType(nestedType, bindingAttr, name, false, ns))
{
if (match != null)
throw ThrowHelper.GetAmbiguousMatchException(match);

match = nestedType;

if (ignoreAmbiguousMatch)
break;
}
}

return match;
}

[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
public override Type? GetNestedType(string name, BindingFlags bindingAttr)
{
return GetNestedType(name, bindingAttr, ignoreAmbiguousMatch: false);
}

[DynamicallyAccessedMembers(GetAllMembers)]
public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr)
{
Expand Down
16 changes: 8 additions & 8 deletions src/mono/System.Private.CoreLib/src/System/Type.Mono.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,53 +30,53 @@ internal IntPtr GetUnderlyingNativeHandle()
public static Type? GetType(string typeName, bool throwOnError, bool ignoreCase)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return GetType(typeName, null, null, throwOnError, ignoreCase, false, ref stackMark);
return RuntimeType.GetType(typeName, throwOnError, ignoreCase, ref stackMark);
}

[RequiresUnreferencedCode("The type might be removed")]
[System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static Type? GetType(string typeName, bool throwOnError)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return GetType(typeName, null, null, throwOnError, false, false, ref stackMark);
return RuntimeType.GetType(typeName, throwOnError, false, ref stackMark);
}

[RequiresUnreferencedCode("The type might be removed")]
[System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static Type? GetType(string typeName)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return GetType(typeName, null, null, false, false, false, ref stackMark);
return RuntimeType.GetType(typeName, false, false, ref stackMark);
}

[RequiresUnreferencedCode("The type might be removed")]
[System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static Type? GetType(string typeName, Func<AssemblyName, Assembly?>? assemblyResolver, Func<Assembly?, string, bool, Type?>? typeResolver)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return GetType(typeName, assemblyResolver, typeResolver, false, false, true, ref stackMark);
return GetType(typeName, assemblyResolver, typeResolver, false, false, ref stackMark);
}

[RequiresUnreferencedCode("The type might be removed")]
[System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static Type? GetType(string typeName, Func<AssemblyName, Assembly?>? assemblyResolver, Func<Assembly?, string, bool, Type?>? typeResolver, bool throwOnError)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return GetType(typeName, assemblyResolver, typeResolver, throwOnError, false, true, ref stackMark);
return GetType(typeName, assemblyResolver, typeResolver, throwOnError, false, ref stackMark);
}

[RequiresUnreferencedCode("The type might be removed")]
[System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static Type? GetType(string typeName, Func<AssemblyName, Assembly?>? assemblyResolver, Func<Assembly?, string, bool, Type?>? typeResolver, bool throwOnError, bool ignoreCase)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return GetType(typeName, assemblyResolver, typeResolver, throwOnError, ignoreCase, true, ref stackMark);
return GetType(typeName, assemblyResolver, typeResolver, throwOnError, ignoreCase, ref stackMark);
}

[RequiresUnreferencedCode("The type might be removed")]
private static Type? GetType(string typeName, Func<AssemblyName, Assembly?>? assemblyResolver, Func<Assembly?, string, bool, Type?>? typeResolver, bool throwOnError, bool ignoreCase, bool extensibleParser, ref StackCrawlMark stackMark)
private static Type? GetType(string typeName, Func<AssemblyName, Assembly?>? assemblyResolver, Func<Assembly?, string, bool, Type?>? typeResolver, bool throwOnError, bool ignoreCase, ref StackCrawlMark stackMark)
{
return TypeNameResolver.GetType(typeName, assemblyResolver, typeResolver, throwOnError, ignoreCase, extensibleParser, ref stackMark);
return TypeNameResolver.GetType(typeName, assemblyResolver, typeResolver, throwOnError, ignoreCase, ref stackMark);
}

public static Type? GetTypeFromHandle(RuntimeTypeHandle handle)
Expand Down
Loading