diff options
author | Atsushi Kanamori <AtsushiKan@users.noreply.github.com> | 2017-06-22 23:43:22 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-22 23:43:22 +0300 |
commit | 919f5ed26ad78940d126d25368d036e6cdb44f00 (patch) | |
tree | 2dbc3592a4ccf8f136d05558311c0b1d0aef0a5a /src/System.Private.Reflection.Core | |
parent | 6b34633f22161063a311605d830742363f105926 (diff) |
Implement Assembly.GetForwardedTypes() on CoreRT/ProjectN (#3967)
See https://github.com/dotnet/corefx/issues/19789
for specifications.
Diffstat (limited to 'src/System.Private.Reflection.Core')
5 files changed, 145 insertions, 0 deletions
diff --git a/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj b/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj index 30f3206ea..8e87be884 100644 --- a/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj +++ b/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj @@ -124,6 +124,7 @@ <Compile Include="System\Reflection\Runtime\General\ThunkedApis.cs" /> <Compile Include="System\Reflection\Runtime\General\ToStringUtils.cs" /> <Compile Include="System\Reflection\Runtime\General\TypeContext.cs" /> + <Compile Include="System\Reflection\Runtime\General\TypeForwardInfo.cs" /> <Compile Include="System\Reflection\Runtime\General\TypeResolver.cs" /> <Compile Include="System\Reflection\Runtime\General\TypeResolver.NativeFormat.cs" /> <Compile Include="System\Reflection\Runtime\General\TypeUnifier.cs" /> diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/EcmaFormat/EcmaFormatRuntimeAssembly.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/EcmaFormat/EcmaFormatRuntimeAssembly.cs index 1885a7731..0b27a36d4 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/EcmaFormat/EcmaFormatRuntimeAssembly.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/EcmaFormat/EcmaFormatRuntimeAssembly.cs @@ -96,6 +96,30 @@ namespace System.Reflection.Runtime.Assemblies.EcmaFormat } } + protected sealed override IEnumerable<TypeForwardInfo> TypeForwardInfos + { + get + { + MetadataReader reader = MetadataReader; + foreach (ExportedTypeHandle exportedTypeHandle in reader.ExportedTypes) + { + ExportedType exportedType = reader.GetExportedType(exportedTypeHandle); + if (!exportedType.IsForwarder) + continue; + + EntityHandle implementation = exportedType.Implementation; + if (implementation.Kind != HandleKind.AssemblyReference) // This check also weeds out nested types. This is intentional. + continue; + RuntimeAssemblyName redirectedAssemblyName = ((AssemblyReferenceHandle)implementation).ToRuntimeAssemblyName(reader); + + string typeName = exportedType.Name.GetString(reader); + string namespaceName = exportedType.Namespace.GetString(reader); + + yield return new TypeForwardInfo(redirectedAssemblyName, namespaceName, typeName); + } + } + } + private unsafe struct InternalManifestResourceInfo { public bool Found; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs index b8ff628fb..317e44ebe 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs @@ -120,6 +120,37 @@ namespace System.Reflection.Runtime.Assemblies.NativeFormat } } + protected sealed override IEnumerable<TypeForwardInfo> TypeForwardInfos + { + get + { + foreach (QScopeDefinition scope in AllScopes) + { + MetadataReader reader = scope.Reader; + ScopeDefinition scopeDefinition = scope.ScopeDefinition; + IEnumerable<NamespaceDefinitionHandle> topLevelNamespaceHandles = new NamespaceDefinitionHandle[] { scopeDefinition.RootNamespaceDefinition }; + IEnumerable<NamespaceDefinitionHandle> allNamespaceHandles = reader.GetTransitiveNamespaces(topLevelNamespaceHandles); + foreach (NamespaceDefinitionHandle namespaceHandle in allNamespaceHandles) + { + string namespaceName = null; + foreach (TypeForwarderHandle typeForwarderHandle in namespaceHandle.GetNamespaceDefinition(reader).TypeForwarders) + { + if (namespaceName == null) + { + namespaceName = namespaceHandle.ToNamespaceName(reader); + } + + TypeForwarder typeForwarder = typeForwarderHandle.GetTypeForwarder(reader); + string typeName = typeForwarder.Name.GetString(reader); + RuntimeAssemblyName redirectedAssemblyName = typeForwarder.Scope.ToRuntimeAssemblyName(reader); + + yield return new TypeForwardInfo(redirectedAssemblyName, namespaceName, typeName); + } + } + } + } + } + public sealed override ManifestResourceInfo GetManifestResourceInfo(String resourceName) { return ReflectionCoreExecution.ExecutionEnvironment.GetManifestResourceInfo(this, resourceName); diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssembly.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssembly.cs index 3e5b3b86a..353a3757c 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssembly.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssembly.cs @@ -125,6 +125,69 @@ namespace System.Reflection.Runtime.Assemblies return RuntimeAssemblyName.ToAssemblyName(); } + public sealed override Type[] GetForwardedTypes() + { + List<Type> types = new List<Type>(); + List<Exception> exceptions = null; + + foreach (TypeForwardInfo typeForwardInfo in TypeForwardInfos) + { + string fullTypeName = typeForwardInfo.NamespaceName.Length == 0 ? typeForwardInfo.TypeName : typeForwardInfo.NamespaceName + "." + typeForwardInfo.TypeName; + RuntimeAssemblyName redirectedAssemblyName = typeForwardInfo.RedirectedAssemblyName; + + Type type = null; + RuntimeAssembly redirectedAssembly; + Exception exception = RuntimeAssembly.TryGetRuntimeAssembly(redirectedAssemblyName, out redirectedAssembly); + if (exception == null) + { + type = redirectedAssembly.GetTypeCore(fullTypeName, ignoreCase: false); // GetTypeCore() will follow any further type-forwards if needed. + if (type == null) + exception = Helpers.CreateTypeLoadException(fullTypeName.EscapeTypeNameIdentifier(), redirectedAssembly); + } + + Debug.Assert((type != null) != (exception != null)); // Exactly one of these must be non-null. + + if (type != null) + { + types.Add(type); + AddPublicNestedTypes(type, types); + } + else + { + if (exceptions == null) + { + exceptions = new List<Exception>(); + } + exceptions.Add(exception); + } + } + + if (exceptions != null) + { + int numTypes = types.Count; + int numExceptions = exceptions.Count; + types.AddRange(new Type[numExceptions]); // add one null Type for each exception. + exceptions.InsertRange(0, new Exception[numTypes]); // align the Exceptions with the null Types. + throw new ReflectionTypeLoadException(types.ToArray(), exceptions.ToArray()); + } + + return types.ToArray(); + } + + /// <summary> + /// Intentionally excludes forwards to nested types. + /// </summary> + protected abstract IEnumerable<TypeForwardInfo> TypeForwardInfos { get; } + + private static void AddPublicNestedTypes(Type type, List<Type> types) + { + foreach (Type nestedType in type.GetNestedTypes(BindingFlags.Public)) + { + types.Add(nestedType); + AddPublicNestedTypes(nestedType, types); + } + } + /// <summary> /// Helper routine for the more general Type.GetType() family of apis. /// diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeForwardInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeForwardInfo.cs new file mode 100644 index 000000000..600eaaad4 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeForwardInfo.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace System.Reflection.Runtime.General +{ + internal struct TypeForwardInfo + { + public TypeForwardInfo(RuntimeAssemblyName redirectedAssemblyName, string namespaceName, string typeName) + { + Debug.Assert(redirectedAssemblyName != null); + Debug.Assert(namespaceName != null); + Debug.Assert(typeName != null); + + RedirectedAssemblyName = redirectedAssemblyName; + NamespaceName = namespaceName; + TypeName = typeName; + } + + public RuntimeAssemblyName RedirectedAssemblyName { get; } + public string NamespaceName { get; } + public string TypeName { get; } + } +} |