From ba3e0953f8fa115684b2931133caf46a9972b3ec Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Fri, 19 May 2017 15:43:07 -0700 Subject: [PATCH] Additional tests for refout. Additional argument check on IncludePrivateMembers (#19478) --- .../Portable/CSharpResources.Designer.cs | 31 +- .../CSharp/Portable/CSharpResources.resx | 2 +- .../Test/Emit/Emit/CompilationEmitTests.cs | 388 ++++++++++++++++-- .../CodeAnalysisResources.Designer.cs | 9 + .../Core/Portable/CodeAnalysisResources.resx | 3 + .../Core/Portable/Compilation/Compilation.cs | 5 + .../Test/Emit/Emit/CompilationEmitTests.vb | 176 +++++++- 7 files changed, 563 insertions(+), 51 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 2791e8b9a45ea..6544acbdfb2eb 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -5938,15 +5938,6 @@ internal static string ERR_LookupInTypeVariable { } } - /// - /// Looks up a localized string similar to '{0}': an entry point cannot be marked with the 'async' modifier. - /// - internal static string ERR_MainCantBeAsync { - get { - return ResourceManager.GetString("ERR_MainCantBeAsync", resourceCulture); - } - } - /// /// Looks up a localized string similar to Cannot use '{0}' for Main method because it is imported. /// @@ -6182,7 +6173,7 @@ internal static string ERR_MissingDebugSwitch { } /// - /// Looks up a localized string similar to No Deconstruct instance or extension method was found for type '{0}', with {1} out parameters and a void return type.. + /// Looks up a localized string similar to No suitable Deconstruct instance or extension method was found for type '{0}', with {1} out parameters and a void return type.. /// internal static string ERR_MissingDeconstruct { get { @@ -6882,18 +6873,16 @@ internal static string ERR_NonInvocableMemberCalled { return ResourceManager.GetString("ERR_NonInvocableMemberCalled", resourceCulture); } } - + /// - /// Looks up a localized string similar to Async Main methods must return Task or Task<int>. + /// Looks up a localized string similar to A void or int returning entry point cannot be async. /// - internal static string ERR_NonTaskMainCantBeAsync - { - get - { + internal static string ERR_NonTaskMainCantBeAsync { + get { return ResourceManager.GetString("ERR_NonTaskMainCantBeAsync", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot embed interop types from assembly '{0}' because it is missing the '{1}' attribute.. /// @@ -9890,7 +9879,7 @@ internal static string IDS_Covariantly { return ResourceManager.GetString("IDS_Covariantly", resourceCulture); } } - + /// /// Looks up a localized string similar to /// Visual C# Compiler Options @@ -9904,10 +9893,8 @@ internal static string IDS_Covariantly { /// /t:winexe) /// /target:library [rest of string was truncated]";. /// - internal static string IDS_CSCHelp - { - get - { + internal static string IDS_CSCHelp { + get { return ResourceManager.GetString("IDS_CSCHelp", resourceCulture); } } diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 83c5a43e3f1b4..bd36370f4437a 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4884,7 +4884,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ tuples - No Deconstruct instance or extension method was found for type '{0}', with {1} out parameters and a void return type. + No suitable Deconstruct instance or extension method was found for type '{0}', with {1} out parameters and a void return type. Deconstruct assignment requires an expression with a type on the right-hand-side. diff --git a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs index db307fc169220..e2ce4a0391ebc 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs @@ -737,36 +737,17 @@ void verifyRefOnly(MetadataReference reference) { var comp = CreateStandardCompilation(source, options: TestOptions.ReleaseDll, references: new MetadataReference[] { reference }); - using (var output = new MemoryStream()) - { - EmitResult emitResult = comp.Emit(output, - options: new EmitOptions(includePrivateMembers: false).WithEmitMetadataOnly(true)); - Assert.True(emitResult.Success); - emitResult.Diagnostics.Verify(); - - var refImage = output.ToImmutable(); - verifyNoPia(refImage, expectMissing: true); - } + var refOnlyImage = EmitRefOnly(comp); + verifyNoPia(refOnlyImage, expectMissing: true); } void verifyRefOut(MetadataReference reference) { var comp = CreateStandardCompilation(source, options: TestOptions.ReleaseDll, references: new MetadataReference[] { reference }); - using (var output = new MemoryStream()) - using (var metadataOutput = new MemoryStream()) - { - EmitResult emitResult = comp.Emit(output, metadataPEStream: metadataOutput, - options: new EmitOptions(includePrivateMembers: false)); - Assert.True(emitResult.Success); - emitResult.Diagnostics.Verify(); - - var image = output.ToImmutable(); - var refImage = metadataOutput.ToImmutable(); - - verifyNoPia(image, expectMissing: false); - verifyNoPia(refImage, expectMissing: false); - } + var (image, refImage) = EmitRefOut(comp); + verifyNoPia(image, expectMissing: false); + verifyNoPia(refImage, expectMissing: false); } // The ref assembly produced by refout has more types than that produced by refonly, @@ -787,7 +768,7 @@ void verifyNoPia(ImmutableArray image, bool expectMissing) return; } - Assert.NotNull(itest1.GetAttribute("System.Runtime.InteropServices", "TypeIdentifierAttribute").ToString()); + Assert.NotNull(itest1.GetAttribute("System.Runtime.InteropServices", "TypeIdentifierAttribute")); var method = (PEMethodSymbol)itest1.GetMember("M"); Assert.Equal("S ITest1.M()", method.ToTestDisplayString()); @@ -877,6 +858,7 @@ public struct S { private object _field; public static S GetValue() => new S() { _field = new object() }; + public object GetField() => _field; }", @"class C { @@ -915,6 +897,292 @@ I1 M(A a) comp => comp.VerifyDiagnostics()); } + [Fact] + public void RefAssemblyClient_EmitTupleNames() + { + VerifyRefAssemblyClient(@" +public class A +{ + public (int first, int) field; +}", +@"class C +{ + void M(A a) + { + System.Console.Write(a.field.first); + } +}", +comp => comp.VerifyDiagnostics()); + } + + [Fact] + public void RefAssemblyClient_EmitDynamic() + { + VerifyRefAssemblyClient(@" +public class A +{ + public dynamic field; +}", +@"class C +{ + void M(A a) + { + System.Console.Write(a.field.DynamicMethod()); + } +}", +comp => comp.VerifyDiagnostics()); + } + + [Fact] + public void RefAssemblyClient_EmitOut() + { + VerifyRefAssemblyClient(@" +public class A +{ + public void M(out int x) { x = 1; } +}", +@"class C +{ + void M(A a) + { + a.M(out int x); + } +}", +comp => comp.VerifyDiagnostics()); + } + + [Fact] + public void RefAssemblyClient_EmitVariance_OutError() + { + VerifyRefAssemblyClient(@" +public interface I +{ +}", +@" +class Base { } +class Derived : Base +{ + I M(I x) + { + return x; + } +}", +comp => comp.VerifyDiagnostics( + // (7,16): error CS0266: Cannot implicitly convert type 'I' to 'I'. An explicit conversion exists (are you missing a cast?) + // return x; + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("I", "I").WithLocation(7, 16) + )); + } + + [Fact] + public void RefAssemblyClient_EmitVariance_OutSuccess() + { + VerifyRefAssemblyClient(@" +public interface I +{ +}", +@" +class Base { } +class Derived : Base +{ + I M(I x) + { + return x; + } +}", +comp => comp.VerifyDiagnostics()); + } + + [Fact] + public void RefAssemblyClient_EmitVariance_InSuccess() + { + VerifyRefAssemblyClient(@" +public interface I +{ +}", +@" +class Base { } +class Derived : Base +{ + I M(I x) + { + return x; + } +}", +comp => comp.VerifyDiagnostics()); + } + + [Fact] + public void RefAssemblyClient_EmitVariance_InError() + { + VerifyRefAssemblyClient(@" +public interface I +{ +}", +@" +class Base { } +class Derived : Base +{ + I M(I x) + { + return x; + } +}", +comp => comp.VerifyDiagnostics( + // (7,16): error CS0266: Cannot implicitly convert type 'I' to 'I'. An explicit conversion exists (are you missing a cast?) + // return x; + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("I", "I").WithLocation(7, 16) + )); + } + + [Fact] + public void RefAssemblyClient_EmitOptionalArguments() + { + VerifyRefAssemblyClient(@" +public class A +{ + public void M(int x = 42) { } +}", +@" +class C +{ + void M2(A a) + { + a.M(); + } +}", +comp => +{ + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp); + verifier.VerifyIL("C.M2", @" +{ + // Code size 11 (0xb) + .maxstack 2 + IL_0000: nop + IL_0001: ldarg.1 + IL_0002: ldc.i4.s 42 + IL_0004: callvirt ""void A.M(int)"" + IL_0009: nop + IL_000a: ret +}"); +}); + } + + [Fact] + public void RefAssemblyClient_EmitArgumentNames() + { + VerifyRefAssemblyClient(@" +public class Base +{ + public virtual void M(int x) { } +} +public class Derived : Base +{ + public override void M(int different) { } +}", +@" +class C +{ + void M2(Derived d) + { + d.M(different: 1); + } +}", +comp => comp.VerifyDiagnostics()); + } + + [Fact] + public void RefAssemblyClient_EmitEnum() + { + VerifyRefAssemblyClient(@" +public enum E +{ + Default, + Other +}", +@" +class C +{ + void M2(E e) + { + System.Console.Write(E.Other); + } +}", +comp => comp.VerifyDiagnostics()); + } + + [Fact] + public void RefAssemblyClient_EmitConst() + { + VerifyRefAssemblyClient(@" +public class A +{ + public const int number = 42; +}", +@" +class C +{ + void M2() + { + System.Console.Write(A.number); + } +}", +comp => +{ + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp); + verifier.VerifyIL("C.M2", @" +{ + // Code size 10 (0xa) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.s 42 + IL_0003: call ""void System.Console.Write(int)"" + IL_0008: nop + IL_0009: ret +}"); + }); + } + + [Fact] + public void RefAssemblyClient_EmitParams() + { + VerifyRefAssemblyClient(@" +public class A +{ + public void M(params int[] x) { } +}", +@" +class C +{ + void M2(A a) + { + a.M(1, 2, 3); + } +}", +comp => comp.VerifyDiagnostics()); + } + + [Fact] + public void RefAssemblyClient_EmitExtension() + { + VerifyRefAssemblyClient(@" +public static class A +{ + public static void M(this string x) { } +}", +@" +class C +{ + void M2(string s) + { + s.M(); + } +}", +comp => comp.VerifyDiagnostics()); + } + [Fact] public void RefAssemblyClient_EmitAllTypes() { @@ -934,6 +1202,22 @@ I1 M(A a) comp => comp.VerifyDiagnostics()); } + [Fact] + public void RefAssemblyClient_EmitNestedTypes() + { + VerifyRefAssemblyClient(@" +public class A +{ + public class Nested { } +} +", +@"class C +{ + void M(A.Nested a) { } +}", +comp => comp.VerifyDiagnostics()); + } + [Fact] public void RefAssemblyClient_StructWithPrivateGenericField() { @@ -941,6 +1225,8 @@ public void RefAssemblyClient_StructWithPrivateGenericField() public struct Container { private T contained; + public void SetField(T value) { contained = value; } + public T GetField() => contained; }", @"public struct Usage { @@ -994,6 +1280,10 @@ public void RefAssemblyClient_StructWithPrivateIntField() public struct S { private int i; + private void M() + { + System.Console.Write(i++); + } }", @"class C { @@ -1041,11 +1331,13 @@ private void VerifyRefAssemblyClient(string lib_cs, string client_cs, Action validator, EmitOptions emitOptions) { string name = GetUniqueName(); - var libComp = CreateStandardCompilation(Parse(lib_cs), + var libComp = CreateStandardCompilation(Parse(lib_cs), references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, SystemCoreRef }, options: TestOptions.DebugDll.WithDeterministic(true), assemblyName: name); + libComp.VerifyDiagnostics(); var libImage = libComp.EmitToImageReference(emitOptions); - var comp = CreateStandardCompilation(source, references: new[] { libImage }, options: TestOptions.DebugDll.WithAllowUnsafe(true)); + var comp = CreateStandardCompilation(source, references: new[] { libImage, ValueTupleRef, SystemRuntimeFacadeRef }, + options: TestOptions.DebugDll.WithAllowUnsafe(true)); validator(comp); } @@ -1368,6 +1660,35 @@ internal struct InternalStruct compWithRef.GetMember("InternalStruct").GetMembers().Select(m => m.ToTestDisplayString())); } + [Fact] + public void RefAssembly_VerifyTypesAndMembersOnPrivateStruct() + { + string source = @" +struct S +{ + private class PrivateType { } + private PrivateType field; +} +"; + CSharpCompilation comp = CreateCompilation(source, references: new[] { MscorlibRef }, + options: TestOptions.DebugDll.WithDeterministic(true)); + + // verify metadata (types, members, attributes) of the ref assembly + var emitRefOnly = EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(false); + CompileAndVerify(comp, emitOptions: emitRefOnly, verify: true); + + var refImage = comp.EmitToImageReference(emitRefOnly); + var compWithRef = CreateCompilation("", references: new[] { MscorlibRef, refImage }, + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + AssertEx.Equal( + new[] { "", "S" }, + compWithRef.SourceModule.GetReferencedAssemblySymbols().Last().GlobalNamespace.GetMembers().Select(m => m.ToDisplayString())); + + AssertEx.Equal( + new[] { "S.PrivateType S.field", "S..ctor()", "S.PrivateType" }, + compWithRef.GetMember("S").GetMembers().Select(m => m.ToTestDisplayString())); + } + [Fact] public void EmitMetadataOnly_DisallowPdbs() { @@ -1410,6 +1731,19 @@ public void IncludePrivateMembers_DisallowMetadataPeStream() } } + [Fact] + public void MustIncludePrivateMembersUnlessRefAssembly() + { + CSharpCompilation comp = CreateCompilation("", references: new[] { MscorlibRef }, + options: TestOptions.DebugDll.WithDeterministic(true)); + + using (var output = new MemoryStream()) + { + Assert.Throws(() => comp.Emit(output, + options: EmitOptions.Default.WithIncludePrivateMembers(false))); + } + } + [Fact] public void EmitMetadata_DisallowOutputtingNetModule() { diff --git a/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs b/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs index 695a46b14854c..128f8df04c488 100644 --- a/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs +++ b/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs @@ -955,6 +955,15 @@ internal static string MultithreadedAnalyzerExecutionNote { } } + /// + /// Looks up a localized string similar to Must include private members unless emitting a ref assembly.. + /// + internal static string MustIncludePrivateMembersUnlessRefAssembly { + get { + return ResourceManager.GetString("MustIncludePrivateMembersUnlessRefAssembly", resourceCulture); + } + } + /// /// Looks up a localized string similar to Name cannot be empty.. /// diff --git a/src/Compilers/Core/Portable/CodeAnalysisResources.resx b/src/Compilers/Core/Portable/CodeAnalysisResources.resx index 514f05c91a1a0..17dde4a37fd63 100644 --- a/src/Compilers/Core/Portable/CodeAnalysisResources.resx +++ b/src/Compilers/Core/Portable/CodeAnalysisResources.resx @@ -339,6 +339,9 @@ Including private members should not be used when emitting to the secondary assembly output. + + Must include private members unless emitting a ref assembly. + Embedding PDB is not allowed when emitting metadata. diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index e29aa55a9d416..3ea6eb9df3c7f 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -2086,6 +2086,11 @@ public EmitResult Emit( throw new ArgumentException(CodeAnalysisResources.IncludingPrivateMembersUnexpectedWhenEmittingToMetadataPeStream, nameof(metadataPEStream)); } + if (metadataPEStream == null && options?.EmitMetadataOnly == false && options?.IncludePrivateMembers == false) + { + throw new ArgumentException(CodeAnalysisResources.MustIncludePrivateMembersUnlessRefAssembly, nameof(options.IncludePrivateMembers)); + } + if (options?.DebugInformationFormat == DebugInformationFormat.Embedded && options?.EmitMetadataOnly == true) { diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/CompilationEmitTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/CompilationEmitTests.vb index 493a56abe6ea4..997e5d15f83f0 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/CompilationEmitTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/CompilationEmitTests.vb @@ -33,7 +33,7 @@ End Module ) - Dim emitResult As emitResult + Dim emitResult As EmitResult Using output = New MemoryStream() emitResult = compilation.Emit(output, Nothing, Nothing, Nothing) @@ -537,6 +537,180 @@ End Function", Match.BothMetadataAndRefOut) End Sub + + Public Sub RefAssemblyNoPia() + Dim piaSource = + + +Public Structure S + Public Dim field As Integer +End Structure + + +Public Interface ITest1 + Function M() As S +End Interface +]]> + Dim pia = CreateCompilationWithMscorlib(piaSource) + CompileAndVerify(pia) + Dim source = + + Dim piaImageReference = pia.EmitToImageReference(embedInteropTypes:=True) + RefAssemblyNoPia_VerifyRefOnly(source, piaImageReference) + RefAssemblyNoPia_VerifyRefOut(source, piaImageReference) + + Dim piaMetadataReference = pia.ToMetadataReference(embedInteropTypes:=True) + RefAssemblyNoPia_VerifyRefOnly(source, piaMetadataReference) + RefAssemblyNoPia_VerifyRefOut(source, piaMetadataReference) + End Sub + + Private Sub RefAssemblyNoPia_VerifyRefOnly(source As Xml.Linq.XElement, reference As MetadataReference) + Dim comp = CreateCompilationWithMscorlib(source, options:=TestOptions.ReleaseDll, references:={reference}) + Dim refOnlyImage = EmitRefOnly(comp) + RefAssemblyNoPia_VerifyNoPia(refOnlyImage) + End Sub + + Private Sub RefAssemblyNoPia_VerifyRefOut(source As Xml.Linq.XElement, reference As MetadataReference) + Dim comp = CreateCompilationWithMscorlib(source, options:=TestOptions.DebugDll, references:={reference}) + Dim pair = EmitRefOut(comp) + RefAssemblyNoPia_VerifyNoPia(pair.image) + RefAssemblyNoPia_VerifyNoPia(pair.refImage) + End Sub + + Private Sub RefAssemblyNoPia_VerifyNoPia(image As ImmutableArray(Of Byte)) + Dim reference = CompilationVerifier.LoadTestEmittedExecutableForSymbolValidation(image, OutputKind.DynamicallyLinkedLibrary) + Dim comp = CreateCompilationWithMscorlib("", references:={reference}) + Dim referencedAssembly = comp.GetReferencedAssemblySymbol(reference) + Dim [module] = DirectCast(referencedAssembly.Modules(0), PEModuleSymbol) + + Dim itest1 = [module].GlobalNamespace.GetMember(Of NamedTypeSymbol)("ITest1") + Assert.NotNull(itest1.GetAttributes().Where(Function(a) a.IsTargetAttribute("System.Runtime.InteropServices", "TypeIdentifierAttribute")).Single()) + + Dim method = DirectCast(itest1.GetMember("M"), PEMethodSymbol) + Assert.Equal("Function ITest1.M() As S", method.ToTestDisplayString()) + + Dim s = DirectCast(method.ReturnType, NamedTypeSymbol) + Assert.Equal("S", s.ToTestDisplayString()) + Assert.NotNull(s.GetAttributes().Where(Function(a) a.IsTargetAttribute("System.Runtime.InteropServices", "TypeIdentifierAttribute")).Single()) + + Dim field = s.GetMember("field") + Assert.Equal("S.field As System.Int32", field.ToTestDisplayString()) + End Sub + + + Public Sub RefAssemblyNoPiaReferenceFromMethodBody() + + Dim piaSource = + + +Public Structure S + Public Dim field As Integer +End Structure + + +Public Interface ITest1 + Function M() As S +End Interface +]]> + Dim pia = CreateCompilationWithMscorlib(piaSource) + CompileAndVerify(pia) + Dim source = + + Dim piaImageReference = pia.EmitToImageReference(embedInteropTypes:=True) + RefAssemblyNoPiaReferenceFromMethodBody_VerifyRefOnly(source, piaImageReference) + RefAssemblyNoPiaReferenceFromMethodBody_VerifyRefOut(source, piaImageReference) + + Dim piaMetadataReference = pia.ToMetadataReference(embedInteropTypes:=True) + RefAssemblyNoPiaReferenceFromMethodBody_VerifyRefOnly(source, piaMetadataReference) + RefAssemblyNoPiaReferenceFromMethodBody_VerifyRefOut(source, piaMetadataReference) + End Sub + + Private Sub RefAssemblyNoPiaReferenceFromMethodBody_VerifyRefOnly(source As Xml.Linq.XElement, reference As MetadataReference) + Dim comp = CreateCompilationWithMscorlib(source, options:=TestOptions.ReleaseDll, references:={reference}) + Dim refOnlyImage = EmitRefOnly(comp) + RefAssemblyNoPiaReferenceFromMethodBody_VerifyNoPia(refOnlyImage, expectMissing:=True) + End Sub + + Private Sub RefAssemblyNoPiaReferenceFromMethodBody_VerifyRefOut(source As Xml.Linq.XElement, reference As MetadataReference) + Dim comp = CreateCompilationWithMscorlib(source, options:=TestOptions.ReleaseDll, references:={reference}) + Dim pair = EmitRefOut(comp) + RefAssemblyNoPiaReferenceFromMethodBody_VerifyNoPia(pair.image, expectMissing:=False) + RefAssemblyNoPiaReferenceFromMethodBody_VerifyNoPia(pair.refImage, expectMissing:=False) + End Sub + + ' The ref assembly produced by refout has more types than that produced by refonly, + ' because refout will bind the method bodies (and therefore populate more referenced types). + ' This will be refined in the future. Follow-up issue: https://github.com/dotnet/roslyn/issues/19403 + Private Sub RefAssemblyNoPiaReferenceFromMethodBody_VerifyNoPia(image As ImmutableArray(Of Byte), expectMissing As Boolean) + Dim reference = CompilationVerifier.LoadTestEmittedExecutableForSymbolValidation(image, OutputKind.DynamicallyLinkedLibrary) + Dim comp = CreateCompilationWithMscorlib("", references:={reference}) + Dim referencedAssembly = comp.GetReferencedAssemblySymbol(reference) + Dim [module] = DirectCast(referencedAssembly.Modules(0), PEModuleSymbol) + + Dim itest1Array = [module].GlobalNamespace.GetMembers("ITest1") + If expectMissing Then + Assert.Empty(itest1Array) + Assert.Empty([module].GlobalNamespace.GetMembers("S")) + Return + End If + + Dim itest1 = DirectCast(itest1Array.Single(), PENamedTypeSymbol) + Assert.NotNull(itest1.GetAttributes().Where(Function(a) a.IsTargetAttribute("System.Runtime.InteropServices", "TypeIdentifierAttribute")).Single()) + + Dim method = DirectCast(itest1.GetMembers("M").Single(), PEMethodSymbol) + Assert.Equal("Function ITest1.M() As S", method.ToTestDisplayString()) + + Dim s = DirectCast(method.ReturnType, NamedTypeSymbol) + Assert.Equal("S", s.ToTestDisplayString()) + Assert.NotNull(s.GetAttributes().Where(Function(a) a.IsTargetAttribute("System.Runtime.InteropServices", "TypeIdentifierAttribute")).Single()) + + Dim field = s.GetMember("field") + Assert.Equal("S.field As System.Int32", field.ToTestDisplayString()) + End Sub + + Private Shared Function EmitRefOut(comp As VisualBasicCompilation) As (image As ImmutableArray(Of Byte), refImage As ImmutableArray(Of Byte)) + Using output = New MemoryStream() + Using metadataOutput = New MemoryStream() + Dim options = EmitOptions.Default.WithIncludePrivateMembers(False) + comp.VerifyEmitDiagnostics() + Dim result = comp.Emit(output, metadataPEStream:=metadataOutput, options:=options) + Return (output.ToImmutable(), metadataOutput.ToImmutable()) + End Using + End Using + End Function + + Private Shared Function EmitRefOnly(comp As VisualBasicCompilation) As ImmutableArray(Of Byte) + Using output = New MemoryStream() + Dim options = EmitOptions.Default.WithEmitMetadataOnly(True).WithIncludePrivateMembers(False) + comp.VerifyEmitDiagnostics() + Dim result = comp.Emit(output, options:=options) + Return output.ToImmutable() + End Using + End Function + Public Sub RefAssembly_InvariantToSomeChangesWithInternalsVisibleTo() Dim sourceTemplate As String = "