提交 5edac38d 编写于 作者: A Andy Gocke

Add special case to reference manager for WinMD compilations

When using WinMD projects in the IDE it is easy to run into
a situation where a project references a project and an assembly
and the project also references the assembly.

For example, a C# compilation C1 references a C# WinMD project C2
and a .winmd assembly W1. W1 also references C2.

When binding these references for C1 we hit a problem -- because
the ContentType of a compilation in Roslyn is always Default (the
compiler emits .winmdobjs, which are later turned into .winmds by
winmdexp, the metadata reference from W1 to C2 will never unify
(different ContentTypes). This change modifies the reference manager to
do a special check for this case and see if we are using a winmdobj
compilation and, if so, correctly unify the reference and the
definition.
上级 29f7b1ca
......@@ -1027,6 +1027,8 @@ public override bool DeclaresTheObjectClass
return _assembly.DeclaresTheObjectClass;
}
}
public override Compilation SourceCompilation => null;
}
private sealed class AssemblyDataForCompilation : AssemblyDataForMetadataOrCompilation
......@@ -1130,6 +1132,8 @@ public override bool DeclaresTheObjectClass
return _compilation.DeclaresTheObjectClass;
}
}
public override Compilation SourceCompilation => _compilation;
}
/// <summary>
......
......@@ -23,6 +23,34 @@ public class ReferenceManagerTests : CSharpTestBase
WithCryptoKeyFile(SigningTestHelpers.KeyPairFile).
WithStrongNameProvider(new SigningTestHelpers.VirtualizedStrongNameProvider(ImmutableArray.Create<string>()));
[Fact]
public void WinRtCompilationReferences()
{
var ifaceDef = CreateCompilationWithMscorlib(
@"
public interface ITest
{
}", options: TestOptions.DebugWinMD, assemblyName: "ITest");
ifaceDef.VerifyDiagnostics();
var ifaceImageRef = ifaceDef.EmitToImageReference();
var wimpl = AssemblyMetadata.CreateFromImage(TestResources.WinRt.WImpl).GetReference(display: "WImpl");
var implDef2 = CreateCompilationWithMscorlib(
@"
public class C
{
public static void Main()
{
ITest test = new WImpl();
}
}", references: new MetadataReference[] { ifaceDef.ToMetadataReference(), wimpl },
options: TestOptions.DebugExe);
implDef2.VerifyDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Signing)]
public void VersionUnification_SymbolUsed()
{
......
......@@ -218,3 +218,4 @@ internal virtual bool ApplyUnificationPolicies(ref AssemblyIdentity reference, r
}
}
}
......@@ -57,6 +57,12 @@ internal abstract class AssemblyData
public abstract bool IsLinked { get; }
public abstract bool DeclaresTheObjectClass { get; }
/// <summary>
/// Get the source compilation backing this assembly, if one exists.
/// Returns null otherwise.
/// </summary>
public abstract Compilation SourceCompilation { get; }
}
}
}
......@@ -144,6 +144,8 @@ public override bool DeclaresTheObjectClass
return false;
}
}
public override Compilation SourceCompilation => null;
}
}
}
......@@ -10,6 +10,7 @@
namespace Microsoft.CodeAnalysis
{
using System.Reflection;
using MetadataOrDiagnostic = System.Object;
/// <summary>
......@@ -850,6 +851,32 @@ private static PortableExecutableReference ResolveReferenceDirective(string refe
}
}
// In the IDE it is possible the reference we're looking for is a
// compilation reference to a source assembly. However, if the reference
// is of ContentType WindowsRuntime then the compilation will never
// match since all C#/VB WindowsRuntime compilations output .winmdobjs,
// not .winmds, and the ContentType of a .winmdobj is Default.
// If this is the case, we want to ignore the ContentType mismatch and
// allow the compilation to match the reference.
if (reference.ContentType == AssemblyContentType.WindowsRuntime)
{
for (int i = definitionOffset; i < definitions.Length; i++)
{
var definition = definitions[i].Identity;
var sourceCompilation = definitions[i].SourceCompilation;
if (definition.ContentType == AssemblyContentType.Default &&
sourceCompilation?.Options.OutputKind == OutputKind.WindowsRuntimeMetadata &&
AssemblyIdentityComparer.SimpleNameComparer.Equals(reference.Name, definition.Name) &&
reference.Version.Equals(definition.Version) &&
reference.IsRetargetable == definition.IsRetargetable &&
AssemblyIdentityComparer.CultureComparer.Equals(reference.CultureName, definition.CultureName) &&
AssemblyIdentity.KeysEqual(reference, definition))
{
return new AssemblyReferenceBinding(reference, i);
}
}
}
// As in the native compiler (see IMPORTER::MapAssemblyRefToAid), we compare against the
// compilation (i.e. source) assembly as a last resort. We follow the native approach of
// skipping the public key comparison since we have yet to compute it.
......
......@@ -406,6 +406,8 @@
<None Include="packages.config" />
<None Include="SymbolsTests\netModule\hash_module.cs" />
<None Include="SymbolsTests\NoPia\MissingPIAAttributes.dll" />
<None Include="WinRt\WImpl.il" />
<None Include="WinRt\WImpl.winmd" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Analyzers\AnalyzerTests.resx">
......
......@@ -5,3 +5,4 @@ ilasm W1.il /mdv="WindowsRuntime 1.2" /msv:1.1 /dll /out=W1.winmd
ilasm W2.il /mdv="WindowsRuntime 1.2" /msv:1.1 /dll /out=W2.winmd
ilasm WB.il /mdv="WindowsRuntime 1.2" /msv:1.1 /dll /out=WB.winmd
ilasm WB_Version1.il /mdv="WindowsRuntime 1.2" /msv:1.1 /dll /out=WB_Version1.winmd
ilasm WImpl.il /mdv="WindowsRuntime 1.3" /msv:1.1 /dll /out=WImpl.winmd
.assembly extern windowsruntime ITest {}
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 255:255:255:255
}
.assembly windowsruntime WImpl
{
.hash algorithm 0x00008004
.ver 255:255:255:255
}
.module WImpl.winmd
.class public auto ansi windowsruntime sealed WImpl
extends System.Object
implements [ITest]ITest
{
.method public hidebysig specialname rtspecialname
instance void .ctor() runtime managed
{
}
}
\ No newline at end of file
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated by a tool.
' Runtime Version:4.0.30319.18326
' Runtime Version:4.0.30319.42000
'
' Changes to this file may cause incorrect behavior and will be lost if
' the code is regenerated.
......@@ -104,6 +104,16 @@ Namespace TestResources
End Get
End Property
'''<summary>
''' Looks up a localized resource of type System.Byte[].
'''</summary>
Public Shared ReadOnly Property WImpl() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("WImpl", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' Looks up a localized resource of type System.Byte[].
'''</summary>
......
......@@ -147,4 +147,7 @@
<data name="WinMDPrefixing_dump" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>WinMDPrefixing.ildump;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="WImpl" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>WImpl.winmd;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
......@@ -869,6 +869,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return _assembly.DeclaresTheObjectClass
End Get
End Property
Public Overrides ReadOnly Property SourceCompilation As Compilation
Get
Return Nothing
End Get
End Property
End Class
Private NotInheritable Class AssemblyDataForCompilation
......@@ -955,6 +961,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return _compilation.DeclaresTheObjectClass
End Get
End Property
Public Overrides ReadOnly Property SourceCompilation As Compilation
Get
Return _compilation
End Get
End Property
End Class
''' <summary>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册