diff options
author | David Wrighton <davidwr@microsoft.com> | 2016-05-26 02:10:56 +0300 |
---|---|---|
committer | David Wrighton <davidwr@microsoft.com> | 2016-05-26 02:10:56 +0300 |
commit | ba30ad4bd2a62a479252dc4e1de2625ad7e6a7e6 (patch) | |
tree | 199f70f086134d9627d7f25540c49773a58b3d0d /src/ILCompiler.MetadataTransform | |
parent | 97c1f333b2b39ee9e84e7a4cdfb3cc1fea9017f0 (diff) |
Add support for ExplicitScopeAttribute to metadata generation (#1321)
* Add support for ExplicitScopeAttribute to metadata generation
- Add new IMetadataPolicy member to control the defining module of a type
- Added mixin implementation that works for ExplicitScopeAttribute
- Added WinRT explicit scope defined types in both the primary metadata assembly and same metadata assembly
- Added single file and multi file tests to ensure that both definition and reference to these relocated types is correct
- New tests implemented in seperate assemblies to reduce impact on existing unittests
- Fix handling of throwIfNotFound parameter in ResolveAssembly in TestTypeSystemContext
Diffstat (limited to 'src/ILCompiler.MetadataTransform')
20 files changed, 515 insertions, 22 deletions
diff --git a/src/ILCompiler.MetadataTransform/MetadataTransform.sln b/src/ILCompiler.MetadataTransform/MetadataTransform.sln index cd3add580..39d81a4ce 100644 --- a/src/ILCompiler.MetadataTransform/MetadataTransform.sln +++ b/src/ILCompiler.MetadataTransform/MetadataTransform.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.24711.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILCompiler.MetadataTransform", "src\ILCompiler.MetadataTransform.csproj", "{A965EA82-219D-48F7-AD51-BC030C16CC6F}" EndProject @@ -15,6 +15,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrimaryMetadataAssembly", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleMetadataAssembly", "tests\SampleMetadataAssembly\SampleMetadataAssembly.csproj", "{D29B7395-A925-5B0E-972D-387D2D4BFEC8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsWinrtMetadataAssembly", "tests\WindowsWinrtMetadataAssembly\WindowsWinrtMetadataAssembly.csproj", "{19D0BAA8-8762-4D64-80AF-53D7A2BBC4AE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleWinRTMetadataAssembly", "tests\SampleWinRTMetadataAssembly\SampleWinRTMetadataAssembly.csproj", "{46CDD663-FCCC-4E74-901F-3D9D5A36A0D9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +49,14 @@ Global {D29B7395-A925-5B0E-972D-387D2D4BFEC8}.Debug|Any CPU.Build.0 = Debug|Any CPU {D29B7395-A925-5B0E-972D-387D2D4BFEC8}.Release|Any CPU.ActiveCfg = Release|Any CPU {D29B7395-A925-5B0E-972D-387D2D4BFEC8}.Release|Any CPU.Build.0 = Release|Any CPU + {19D0BAA8-8762-4D64-80AF-53D7A2BBC4AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {19D0BAA8-8762-4D64-80AF-53D7A2BBC4AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {19D0BAA8-8762-4D64-80AF-53D7A2BBC4AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19D0BAA8-8762-4D64-80AF-53D7A2BBC4AE}.Release|Any CPU.Build.0 = Release|Any CPU + {46CDD663-FCCC-4E74-901F-3D9D5A36A0D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {46CDD663-FCCC-4E74-901F-3D9D5A36A0D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {46CDD663-FCCC-4E74-901F-3D9D5A36A0D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {46CDD663-FCCC-4E74-901F-3D9D5A36A0D9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/ILCompiler.MetadataTransform/src/ILCompiler.MetadataTransform.csproj b/src/ILCompiler.MetadataTransform/src/ILCompiler.MetadataTransform.csproj index 36b0647d8..7f9487fe9 100644 --- a/src/ILCompiler.MetadataTransform/src/ILCompiler.MetadataTransform.csproj +++ b/src/ILCompiler.MetadataTransform/src/ILCompiler.MetadataTransform.csproj @@ -28,6 +28,7 @@ </ItemGroup> <ItemGroup> <Compile Include="ILCompiler\Metadata\EntityMap.cs" /> + <Compile Include="ILCompiler\Metadata\ExplicitScopeAssemblyPolicyMixin.cs" /> <Compile Include="ILCompiler\Metadata\IMetadataPolicy.cs" /> <Compile Include="ILCompiler\Metadata\MetadataTransform.cs" /> <Compile Include="ILCompiler\Metadata\MetadataTransformResult.cs" /> diff --git a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/ExplicitScopeAssemblyPolicyMixin.cs b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/ExplicitScopeAssemblyPolicyMixin.cs new file mode 100644 index 000000000..7b08618e5 --- /dev/null +++ b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/ExplicitScopeAssemblyPolicyMixin.cs @@ -0,0 +1,164 @@ +// 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using Cts = Internal.TypeSystem; +using Ecma = System.Reflection.Metadata; + +namespace ILCompiler.Metadata +{ + /// <summary> + /// Mixin helper class to allow easy support for ExplicitScopeAttribute for metadata transformation + /// + /// ExplicitScopeAttribute is used to relocate where a given type appears in metadata from one + /// metadata assembly to another. It must not be used to relocate into an assembly which otherwise + /// exists within the compilation operation. (Current implementation is not reliable in those + /// circumstances, but there is an assert that in debug builds will detect violations.) + /// </summary> + public class ExplicitScopeAssemblyPolicyMixin + { + private class AssemblyNameEqualityComparer : IEqualityComparer<AssemblyName> + { + public static AssemblyNameEqualityComparer Instance { get; } = new AssemblyNameEqualityComparer(); + + public bool ByteArrayCompare(byte[] arr1, byte[] arr2) + { + if (arr1.Length != arr2.Length) + return false; + + for (int i = 0; i < arr1.Length; i++) + { + if (arr1[i] != arr2[i]) + return false; + } + return true; + } + + public bool Equals(AssemblyName x, AssemblyName y) + { + if (x.Name != y.Name) + return false; + + if (x.ContentType != y.ContentType) + return false; + + if (x.CultureName != y.CultureName) + return false; + + if (x.Flags != y.Flags) + return false; + + if (x.Flags.HasFlag(AssemblyNameFlags.PublicKey)) + { + if (!ByteArrayCompare(x.GetPublicKey(), y.GetPublicKey())) + return false; + } + else + { + if (!ByteArrayCompare(x.GetPublicKeyToken(), y.GetPublicKeyToken())) + return false; + } + + if (x.ProcessorArchitecture != y.ProcessorArchitecture) + return false; + + if (!x.Version.Equals(y.Version)) + return false; + + return true; + } + + public int GetHashCode(AssemblyName obj) + { + return obj.Name.GetHashCode(); + } + } + + private class ExplicitScopeAssembly : Cts.ModuleDesc, Cts.IAssemblyDesc + { + AssemblyName _assemblyName; + + public ExplicitScopeAssembly(Cts.TypeSystemContext context, AssemblyName assemblyName) : base(context) + { + _assemblyName = assemblyName; + } + + AssemblyName Cts.IAssemblyDesc.GetName() + { + return _assemblyName; + } + + public override Cts.MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true) + { + if (throwIfNotFound) + throw new TypeLoadException("GetType on an ExplicitScopeAssembly is not supported"); + return null; + } + + public override Cts.TypeDesc GetGlobalModuleType() + { + return null; + } + + public override IEnumerable<Cts.MetadataType> GetAllTypes() + { + return Array.Empty<Cts.MetadataType>(); + } + } + + private Dictionary<AssemblyName, ExplicitScopeAssembly> _dynamicallyGeneratedExplicitScopes = + new Dictionary<AssemblyName, ExplicitScopeAssembly>(AssemblyNameEqualityComparer.Instance); + + private Cts.ModuleDesc OverrideModuleOfTypeViaExplicitScope(Cts.MetadataType typeDef) + { + if (typeDef.HasCustomAttribute("Internal.Reflection", "ExplicitScopeAttribute")) + { + // There is no current cross type system way to represent custom attributes + Cts.Ecma.EcmaType ecmaType = (Cts.Ecma.EcmaType)typeDef; + + var customAttributeValue = Internal.TypeSystem.Ecma.MetadataExtensions.GetDecodedCustomAttribute( + ecmaType, "Internal.Reflection", "ExplicitScopeAttribute"); + + if (!customAttributeValue.HasValue) + return null; + + if (customAttributeValue.Value.FixedArguments.Length != 1) + return null; + + if (customAttributeValue.Value.FixedArguments[0].Type != typeDef.Context.GetWellKnownType(Cts.WellKnownType.String)) + return null; + + string assemblyNameString = (string)customAttributeValue.Value.FixedArguments[0].Value; + AssemblyName assemblyName = new AssemblyName(assemblyNameString); + Debug.Assert(typeDef.Context.ResolveAssembly(assemblyName, false) == null, "ExplicitScopeAttribute must not refer to an assembly which is actually present in the type system."); + lock(_dynamicallyGeneratedExplicitScopes) + { + ExplicitScopeAssembly explicitScopeAssembly; + + if (_dynamicallyGeneratedExplicitScopes.TryGetValue(assemblyName, out explicitScopeAssembly)) + { + return explicitScopeAssembly; + } + explicitScopeAssembly = new ExplicitScopeAssembly(typeDef.Context, assemblyName); + _dynamicallyGeneratedExplicitScopes.Add(assemblyName, explicitScopeAssembly); + return explicitScopeAssembly; + } + } + + return null; + } + + public Cts.ModuleDesc GetModuleOfType(Cts.MetadataType typeDef) + { + Cts.ModuleDesc overrideModule = OverrideModuleOfTypeViaExplicitScope(typeDef); + if (overrideModule != null) + return overrideModule; + + return typeDef.Module; + } + } +} diff --git a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/IMetadataPolicy.cs b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/IMetadataPolicy.cs index e4d407af8..48c3474ae 100644 --- a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/IMetadataPolicy.cs +++ b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/IMetadataPolicy.cs @@ -43,5 +43,11 @@ namespace ILCompiler.Metadata /// blocked types are dropped from metadata. /// </summary> bool IsBlocked(Cts.MetadataType typeDef); + + /// <summary> + /// Return the Module that should be treated as defining the type. Typically implementations + /// will return typeDef.Module, but in some circumstances it may return a different value. + /// </summary> + Cts.ModuleDesc GetModuleOfType(Cts.MetadataType typeDef); } } diff --git a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/MetadataTransform.cs b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/MetadataTransform.cs index 68858f046..f9cbe1250 100644 --- a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/MetadataTransform.cs +++ b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/MetadataTransform.cs @@ -34,7 +34,7 @@ namespace ILCompiler.Metadata // - change the way TypeDefs are hooked up into namespaces and scopes // - queue up calls to the various Initialize* methods on a threadpool - var transform = new Transform<TPolicy>(policy, modules); + var transform = new Transform<TPolicy>(policy); foreach (var module in modules) { diff --git a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Scope.cs b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Scope.cs index 1375c325d..19565baa0 100644 --- a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Scope.cs +++ b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Scope.cs @@ -29,10 +29,6 @@ namespace ILCompiler.Metadata private void InitializeScopeDefinition(Cts.ModuleDesc module, ScopeDefinition scopeDefinition) { - // Make sure we're expected to create a scope definition here. If the assert fires, the metadata - // policy should have directed us to create a scope reference (or the list of inputs was incomplete). - Debug.Assert(_modulesToTransform.Contains(module), "Incomplete list of input modules with respect to metadata policy"); - var assemblyDesc = module as Cts.IAssemblyDesc; if (assemblyDesc != null) { diff --git a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Type.cs b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Type.cs index 7baf9e0cb..982e76ed9 100644 --- a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Type.cs +++ b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.Type.cs @@ -192,7 +192,7 @@ namespace ILCompiler.Metadata } else { - parentReferenceRecord.ParentNamespaceOrType = HandleNamespaceReference(containingType.Module, containingType.Namespace); + parentReferenceRecord.ParentNamespaceOrType = HandleNamespaceReference(_policy.GetModuleOfType(containingType), containingType.Namespace); } return parentReferenceRecord; @@ -208,7 +208,7 @@ namespace ILCompiler.Metadata } else { - record.ParentNamespaceOrType = HandleNamespaceReference(entity.Module, entity.Namespace); + record.ParentNamespaceOrType = HandleNamespaceReference(_policy.GetModuleOfType(entity), entity.Namespace); } record.TypeName = HandleString(entity.Name); @@ -225,12 +225,12 @@ namespace ILCompiler.Metadata enclosingType.NestedTypes.Add(record); var namespaceDefinition = - HandleNamespaceDefinition(entity.ContainingType.Module, entity.ContainingType.Namespace); + HandleNamespaceDefinition(_policy.GetModuleOfType(entity.ContainingType), entity.ContainingType.Namespace); record.NamespaceDefinition = namespaceDefinition; } else { - var namespaceDefinition = HandleNamespaceDefinition(entity.Module, entity.Namespace); + var namespaceDefinition = HandleNamespaceDefinition(_policy.GetModuleOfType(entity), entity.Namespace); record.NamespaceDefinition = namespaceDefinition; namespaceDefinition.TypeDefinitions.Add(record); } diff --git a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.cs b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.cs index d64c5a3fb..ef7554629 100644 --- a/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.cs +++ b/src/ILCompiler.MetadataTransform/src/ILCompiler/Metadata/Transform.cs @@ -20,12 +20,10 @@ namespace ILCompiler.Metadata where TPolicy : struct, IMetadataPolicy { private TPolicy _policy; - private HashSet<Cts.ModuleDesc> _modulesToTransform; - public Transform(TPolicy policy, IEnumerable<Cts.ModuleDesc> modules) + public Transform(TPolicy policy) { _policy = policy; - _modulesToTransform = new HashSet<Cts.ModuleDesc>(modules); } private bool IsBlocked(Cts.TypeDesc type) diff --git a/src/ILCompiler.MetadataTransform/tests/ExplicitScopeTests.cs b/src/ILCompiler.MetadataTransform/tests/ExplicitScopeTests.cs new file mode 100644 index 000000000..6745b23ee --- /dev/null +++ b/src/ILCompiler.MetadataTransform/tests/ExplicitScopeTests.cs @@ -0,0 +1,134 @@ +// 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.Linq; +using Internal.Metadata.NativeFormat.Writer; +using ILCompiler.Metadata; + +using Cts = Internal.TypeSystem; +using NativeFormat = Internal.Metadata.NativeFormat; + +using Xunit; + +namespace MetadataTransformTests +{ + public class ExplicitScopeTests + { + private TestTypeSystemContext _context; + private Cts.Ecma.EcmaModule _systemModule; + + public ExplicitScopeTests() + { + _context = new TestTypeSystemContext(); + _systemModule = _context.CreateModuleForSimpleName("PrimaryMetadataAssembly"); + _context.SetSystemModule(_systemModule); + } + + public ScopeDefinition GetScopeDefinitionOfType(TypeDefinition typeDefinition) + { + Assert.NotNull(typeDefinition); + ScopeDefinition scope = null; + NamespaceDefinition currentNamespaceDefinition = typeDefinition.NamespaceDefinition; + + while (scope == null) + { + Assert.NotNull(currentNamespaceDefinition); + scope = currentNamespaceDefinition.ParentScopeOrNamespace as ScopeDefinition; + currentNamespaceDefinition = currentNamespaceDefinition.ParentScopeOrNamespace as NamespaceDefinition; + } + + return scope; + } + + public ScopeReference GetScopeReferenceOfType(TypeReference typeReference) + { + Assert.NotNull(typeReference); + ScopeReference scope = null; + NamespaceReference currentNamespaceReference = typeReference.ParentNamespaceOrType as NamespaceReference; + + while (scope == null) + { + Assert.NotNull(currentNamespaceReference); + scope = currentNamespaceReference.ParentScopeOrNamespace as ScopeReference; + currentNamespaceReference = currentNamespaceReference.ParentScopeOrNamespace as NamespaceReference; + } + + return scope; + } + + public void CheckTypeDefinitionForProperWinRTHome(TypeDefinition typeDefinition, string module) + { + ScopeDefinition scope = GetScopeDefinitionOfType(typeDefinition); + Assert.Equal(module, scope.Name.Value); + int windowsRuntimeFlag = ((int)System.Reflection.AssemblyContentType.WindowsRuntime << 9); + Assert.True((((int)scope.Flags) & windowsRuntimeFlag) == windowsRuntimeFlag); + } + + + public void CheckTypeReferenceForProperWinRTHome(TypeReference typeReference, string module) + { + ScopeReference scope = GetScopeReferenceOfType(typeReference); + Assert.Equal(module, scope.Name.Value); + int windowsRuntimeFlag = ((int)System.Reflection.AssemblyContentType.WindowsRuntime << 9); + Assert.True((((int)scope.Flags) & windowsRuntimeFlag) == windowsRuntimeFlag); + } + + [Fact] + public void TestExplicitScopeAttributesForWinRTSingleFilePolicy() + { + // Test that custom attributes referring to blocked types don't show up in metadata + + var sampleMetadataModule = _context.GetModuleForSimpleName("SampleMetadataAssembly"); + var sampleWinRTMetadataModule = _context.GetModuleForSimpleName("SampleWinRTMetadataAssembly"); + var windowsWinRTMetadataModule = _context.GetModuleForSimpleName("WindowsWinRTMetadataAssembly"); + + Cts.MetadataType controlType = windowsWinRTMetadataModule.GetType("Windows", "Control"); + Cts.MetadataType derivedFromControl = sampleWinRTMetadataModule.GetType("SampleMetadataWinRT", "DerivedFromControl"); + Cts.MetadataType derivedFromControlInCustomScope = sampleWinRTMetadataModule.GetType("SampleMetadataWinRT", "DerivedFromControlAndInCustomScope"); + + var policy = new SingleFileMetadataPolicy(); + + var transformResult = MetadataTransform.Run(policy, + new[] { _systemModule, sampleMetadataModule, sampleWinRTMetadataModule, windowsWinRTMetadataModule }); + + var controlTypeMetadata = transformResult.GetTransformedTypeDefinition(controlType); + var derivedFromControlMetadata = transformResult.GetTransformedTypeDefinition(derivedFromControl); + var derivedFromControlInCustomScopeMetadata = transformResult.GetTransformedTypeDefinition(derivedFromControlInCustomScope); + + CheckTypeDefinitionForProperWinRTHome(controlTypeMetadata, "Windows"); + ScopeDefinition scopeDefOfDerivedFromControlType = GetScopeDefinitionOfType(derivedFromControlMetadata); + Assert.Equal("SampleWinRTMetadataAssembly", scopeDefOfDerivedFromControlType.Name.Value); + CheckTypeDefinitionForProperWinRTHome(derivedFromControlInCustomScopeMetadata, "SampleMetadataWinRT"); + } + + + [Fact] + public void TestExplicitScopeAttributesForWinRTMultiFilePolicy() + { + // Test that custom attributes referring to blocked types don't show up in metadata + + var sampleMetadataModule = _context.GetModuleForSimpleName("SampleMetadataAssembly"); + var sampleWinRTMetadataModule = _context.GetModuleForSimpleName("SampleWinRTMetadataAssembly"); + var windowsWinRTMetadataModule = _context.GetModuleForSimpleName("WindowsWinRTMetadataAssembly"); + + Cts.MetadataType controlType = windowsWinRTMetadataModule.GetType("Windows", "Control"); + Cts.MetadataType derivedFromControl = sampleWinRTMetadataModule.GetType("SampleMetadataWinRT", "DerivedFromControl"); + Cts.MetadataType derivedFromControlInCustomScope = sampleWinRTMetadataModule.GetType("SampleMetadataWinRT", "DerivedFromControlAndInCustomScope"); + + var policy = new MultifileMetadataPolicy(sampleMetadataModule, sampleWinRTMetadataModule); + + var transformResult = MetadataTransform.Run(policy, + new[] { _systemModule, sampleMetadataModule, sampleWinRTMetadataModule, windowsWinRTMetadataModule }); + + var controlTypeMetadata = transformResult.GetTransformedTypeReference(controlType); + var derivedFromControlMetadata = transformResult.GetTransformedTypeDefinition(derivedFromControl); + var derivedFromControlInCustomScopeMetadata = transformResult.GetTransformedTypeDefinition(derivedFromControlInCustomScope); + + CheckTypeReferenceForProperWinRTHome(controlTypeMetadata, "Windows"); + ScopeDefinition scopeDefOfDerivedFromControlType = GetScopeDefinitionOfType(derivedFromControlMetadata); + Assert.Equal("SampleWinRTMetadataAssembly", scopeDefOfDerivedFromControlType.Name.Value); + CheckTypeDefinitionForProperWinRTHome(derivedFromControlInCustomScopeMetadata, "SampleMetadataWinRT"); + } + } +} diff --git a/src/ILCompiler.MetadataTransform/tests/ILCompiler.MetadataTransform.Tests.csproj b/src/ILCompiler.MetadataTransform/tests/ILCompiler.MetadataTransform.Tests.csproj index bba38298f..8ae05e9ff 100644 --- a/src/ILCompiler.MetadataTransform/tests/ILCompiler.MetadataTransform.Tests.csproj +++ b/src/ILCompiler.MetadataTransform/tests/ILCompiler.MetadataTransform.Tests.csproj @@ -39,11 +39,24 @@ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <Targets>Build;DebugSymbolsProjectOutputGroup</Targets> </ProjectReference> + <ProjectReference Include="SampleWinRTMetadataAssembly\SampleWinRTMetadataAssembly.csproj"> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + <OutputItemType>Content</OutputItemType> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + <Targets>Build;DebugSymbolsProjectOutputGroup</Targets> + </ProjectReference> + <ProjectReference Include="WindowsWinrtMetadataAssembly\WindowsWinrtMetadataAssembly.csproj"> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + <OutputItemType>Content</OutputItemType> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + <Targets>Build;DebugSymbolsProjectOutputGroup</Targets> + </ProjectReference> </ItemGroup> <ItemGroup> <None Include="project.json" /> </ItemGroup> <ItemGroup> + <Compile Include="ExplicitScopeTests.cs" /> <Compile Include="MockPolicy.cs" /> <Compile Include="MultifileMetadataPolicy.cs" /> <Compile Include="NativeFormatExtensions.cs" /> diff --git a/src/ILCompiler.MetadataTransform/tests/MockPolicy.cs b/src/ILCompiler.MetadataTransform/tests/MockPolicy.cs index c262269aa..c87ce5f8b 100644 --- a/src/ILCompiler.MetadataTransform/tests/MockPolicy.cs +++ b/src/ILCompiler.MetadataTransform/tests/MockPolicy.cs @@ -15,17 +15,20 @@ namespace MetadataTransformTests private Func<FieldDesc, bool> _fieldGeneratesMetadata; private Func<MetadataType, bool> _isBlockedType; + private Func<MetadataType, ModuleDesc> _moduleOfType; public MockPolicy( Func<MetadataType, bool> typeGeneratesMetadata, Func<MethodDesc, bool> methodGeneratesMetadata = null, Func<FieldDesc, bool> fieldGeneratesMetadata = null, - Func<MetadataType, bool> isBlockedType = null) + Func<MetadataType, bool> isBlockedType = null, + Func<MetadataType, ModuleDesc> moduleOfType = null) { _typeGeneratesMetadata = typeGeneratesMetadata; _methodGeneratesMetadata = methodGeneratesMetadata; _fieldGeneratesMetadata = fieldGeneratesMetadata; _isBlockedType = isBlockedType; + _moduleOfType = moduleOfType; } public bool GeneratesMetadata(MethodDesc methodDef) @@ -53,5 +56,12 @@ namespace MetadataTransformTests return _isBlockedType(typeDef); return false; } + + public ModuleDesc GetModuleOfType(MetadataType typeDef) + { + if (_moduleOfType != null) + return _moduleOfType(typeDef); + return typeDef.Module; + } } } diff --git a/src/ILCompiler.MetadataTransform/tests/MultifileMetadataPolicy.cs b/src/ILCompiler.MetadataTransform/tests/MultifileMetadataPolicy.cs index 2eb940d96..ac4d25775 100644 --- a/src/ILCompiler.MetadataTransform/tests/MultifileMetadataPolicy.cs +++ b/src/ILCompiler.MetadataTransform/tests/MultifileMetadataPolicy.cs @@ -17,11 +17,13 @@ namespace MetadataTransformTests /// </summary> struct MultifileMetadataPolicy : IMetadataPolicy { + ExplicitScopeAssemblyPolicyMixin _explicitScopePolicyMixin; HashSet<ModuleDesc> _modules; public MultifileMetadataPolicy(params ModuleDesc[] modules) { _modules = new HashSet<ModuleDesc>(modules); + _explicitScopePolicyMixin = new ExplicitScopeAssemblyPolicyMixin(); } public bool GeneratesMetadata(MethodDesc methodDef) @@ -49,5 +51,10 @@ namespace MetadataTransformTests return false; } + + public ModuleDesc GetModuleOfType(MetadataType typeDef) + { + return _explicitScopePolicyMixin.GetModuleOfType(typeDef); + } } } diff --git a/src/ILCompiler.MetadataTransform/tests/PrimaryMetadataAssembly/Platform.cs b/src/ILCompiler.MetadataTransform/tests/PrimaryMetadataAssembly/Platform.cs index 25c809c43..b6bea6761 100644 --- a/src/ILCompiler.MetadataTransform/tests/PrimaryMetadataAssembly/Platform.cs +++ b/src/ILCompiler.MetadataTransform/tests/PrimaryMetadataAssembly/Platform.cs @@ -140,3 +140,11 @@ namespace System.Runtime.CompilerServices } } +namespace Internal.Reflection +{ + public sealed class ExplicitScopeAttribute : System.Attribute + { + public ExplicitScopeAttribute(string explicitScope) + { } + } +} diff --git a/src/ILCompiler.MetadataTransform/tests/SampleMetadataAssembly/SampleMetadata.cs b/src/ILCompiler.MetadataTransform/tests/SampleMetadataAssembly/SampleMetadata.cs index 459d338a7..6ea288ecc 100644 --- a/src/ILCompiler.MetadataTransform/tests/SampleMetadataAssembly/SampleMetadata.cs +++ b/src/ILCompiler.MetadataTransform/tests/SampleMetadataAssembly/SampleMetadata.cs @@ -1650,3 +1650,4 @@ namespace SampleMetadataRex } } + diff --git a/src/ILCompiler.MetadataTransform/tests/SampleWinRTMetadataAssembly/SampleWinRTMetadata.cs b/src/ILCompiler.MetadataTransform/tests/SampleWinRTMetadataAssembly/SampleWinRTMetadata.cs new file mode 100644 index 000000000..028095cba --- /dev/null +++ b/src/ILCompiler.MetadataTransform/tests/SampleWinRTMetadataAssembly/SampleWinRTMetadata.cs @@ -0,0 +1,31 @@ +// 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; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +#pragma warning disable 414 +#pragma warning disable 67 +#pragma warning disable 3009 +#pragma warning disable 3016 +#pragma warning disable 3001 +#pragma warning disable 3015 +#pragma warning disable 169 +#pragma warning disable 649 + +namespace SampleMetadataWinRT +{ + // This class should appear to be in a regular managed module + public class DerivedFromControl : Windows.Control + { } + + // This class should appear to be in a winmd called SampleMetadataWinRT + [global::Internal.Reflection.ExplicitScope("SampleMetadataWinRT, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime")] + public class DerivedFromControlAndInCustomScope : Windows.Control + { + } +} + diff --git a/src/ILCompiler.MetadataTransform/tests/SampleWinRTMetadataAssembly/SampleWinRTMetadataAssembly.csproj b/src/ILCompiler.MetadataTransform/tests/SampleWinRTMetadataAssembly/SampleWinRTMetadataAssembly.csproj new file mode 100644 index 000000000..a6786563b --- /dev/null +++ b/src/ILCompiler.MetadataTransform/tests/SampleWinRTMetadataAssembly/SampleWinRTMetadataAssembly.csproj @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <OutputType>Library</OutputType> + <AssemblyName>SampleWinRTMetadataAssembly</AssemblyName> + <GenerateAssemblyInfo>false</GenerateAssemblyInfo> + <ProjectGuid>{46CDD663-FCCC-4E74-901F-3D9D5A36A0D9}</ProjectGuid> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\PrimaryMetadataAssembly\PrimaryMetadataAssembly.csproj" /> + <ProjectReference Include="..\SampleMetadataAssembly\SampleMetadataAssembly.csproj" /> + <ProjectReference Include="..\WindowsWinrtMetadataAssembly\WindowsWinrtMetadataAssembly.csproj" /> + </ItemGroup> + + <ItemGroup> + <Compile Include="SampleWinRTMetadata.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project>
\ No newline at end of file diff --git a/src/ILCompiler.MetadataTransform/tests/SingleFileMetadataPolicy.cs b/src/ILCompiler.MetadataTransform/tests/SingleFileMetadataPolicy.cs index 049176cbc..c8fab721e 100644 --- a/src/ILCompiler.MetadataTransform/tests/SingleFileMetadataPolicy.cs +++ b/src/ILCompiler.MetadataTransform/tests/SingleFileMetadataPolicy.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Reflection; using ILCompiler.Metadata; using Internal.TypeSystem; @@ -10,6 +11,9 @@ namespace MetadataTransformTests { struct SingleFileMetadataPolicy : IMetadataPolicy { + private static object s_lazyInitThreadSafetyLock = new object(); + private ExplicitScopeAssemblyPolicyMixin _explicitScopePolicyMixin; + public bool GeneratesMetadata(MethodDesc methodDef) { return true; @@ -35,5 +39,19 @@ namespace MetadataTransformTests return false; } + + public ModuleDesc GetModuleOfType(MetadataType typeDef) + { + if (_explicitScopePolicyMixin == null) + { + lock (s_lazyInitThreadSafetyLock) + { + if (_explicitScopePolicyMixin == null) + _explicitScopePolicyMixin = new ExplicitScopeAssemblyPolicyMixin(); + } + } + + return _explicitScopePolicyMixin.GetModuleOfType(typeDef); + } } } diff --git a/src/ILCompiler.MetadataTransform/tests/TestTypeSystemContext.cs b/src/ILCompiler.MetadataTransform/tests/TestTypeSystemContext.cs index 850b4415a..6ae9dbf81 100644 --- a/src/ILCompiler.MetadataTransform/tests/TestTypeSystemContext.cs +++ b/src/ILCompiler.MetadataTransform/tests/TestTypeSystemContext.cs @@ -18,25 +18,40 @@ namespace MetadataTransformTests { Dictionary<string, EcmaModule> _modules = new Dictionary<string, EcmaModule>(StringComparer.OrdinalIgnoreCase); - public EcmaModule GetModuleForSimpleName(string simpleName) + public EcmaModule GetModuleForSimpleName(string simpleName, bool throwIfNotFound = true) { - EcmaModule existingModule; - if (_modules.TryGetValue(simpleName, out existingModule)) - return existingModule; - - return CreateModuleForSimpleName(simpleName); + EcmaModule module; + if (!_modules.TryGetValue(simpleName, out module)) + { + module = CreateModuleForSimpleName(simpleName); + } + + if (module == null && throwIfNotFound) + { + throw new FileNotFoundException(simpleName + ".dll"); + } + return module; } public EcmaModule CreateModuleForSimpleName(string simpleName) { - EcmaModule module = EcmaModule.Create(this, new PEReader(File.OpenRead(simpleName + ".dll"))); + EcmaModule module = null; + try + { + module = EcmaModule.Create(this, new PEReader(File.OpenRead(simpleName + ".dll"))); + } + catch (FileNotFoundException) + { + // FileNotFound is treated as being unable to load the module + } + _modules.Add(simpleName, module); return module; } public override ModuleDesc ResolveAssembly(System.Reflection.AssemblyName name, bool throwIfNotFound) { - return GetModuleForSimpleName(name.Name); + return GetModuleForSimpleName(name.Name, throwIfNotFound); } } } diff --git a/src/ILCompiler.MetadataTransform/tests/WindowsWinrtMetadataAssembly/WindowsWinrtMetadata.cs b/src/ILCompiler.MetadataTransform/tests/WindowsWinrtMetadataAssembly/WindowsWinrtMetadata.cs new file mode 100644 index 000000000..471ffbaa4 --- /dev/null +++ b/src/ILCompiler.MetadataTransform/tests/WindowsWinrtMetadataAssembly/WindowsWinrtMetadata.cs @@ -0,0 +1,25 @@ +// 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; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +#pragma warning disable 414 +#pragma warning disable 67 +#pragma warning disable 3009 +#pragma warning disable 3016 +#pragma warning disable 3001 +#pragma warning disable 3015 +#pragma warning disable 169 +#pragma warning disable 649 + +namespace Windows +{ + [Internal.Reflection.ExplicitScope("Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime")] + public class Control + { + } +} diff --git a/src/ILCompiler.MetadataTransform/tests/WindowsWinrtMetadataAssembly/WindowsWinrtMetadataAssembly.csproj b/src/ILCompiler.MetadataTransform/tests/WindowsWinrtMetadataAssembly/WindowsWinrtMetadataAssembly.csproj new file mode 100644 index 000000000..19a4d2875 --- /dev/null +++ b/src/ILCompiler.MetadataTransform/tests/WindowsWinrtMetadataAssembly/WindowsWinrtMetadataAssembly.csproj @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <OutputType>Library</OutputType> + <AssemblyName>WindowsWinrtMetadataAssembly</AssemblyName> + <GenerateAssemblyInfo>false</GenerateAssemblyInfo> + <ProjectGuid>{19D0BAA8-8762-4D64-80AF-53D7A2BBC4AE}</ProjectGuid> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\PrimaryMetadataAssembly\PrimaryMetadataAssembly.csproj" /> + </ItemGroup> + + <ItemGroup> + <Compile Include="WindowsWinrtMetadata.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project>
\ No newline at end of file |