|
// 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.
#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class EmitMetadata : EmitMetadataTestBase
{
[Fact]
public void InstantiatedGenerics()
{
string source = @"
public class A<T>
{
public class B : A<T>
{
internal class C : B
{}
protected B y1;
protected A<D>.B y2;
}
public class H<S>
{
public class I : A<T>.H<S>
{}
}
internal A<T> x1;
internal A<D> x2;
}
public class D
{
public class K<T>
{
public class L : K<T>
{}
}
}
namespace NS1
{
class E : D
{}
}
class F : A<D>
{}
class G : A<NS1.E>.B
{}
class J : A<D>.H<D>
{}
public class M
{}
public class N : D.K<M>
{}
";
CompileAndVerify(source, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), symbolValidator: module =>
{
var dump = DumpTypeInfo(module).ToString();
AssertEx.AssertEqualToleratingWhitespaceDifferences(@"
<Global>
<type name=""<Module>"" />
<type name=""A"" Of=""T"" base=""System.Object"">
<field name=""x1"" type=""A<T>"" />
<field name=""x2"" type=""A<D>"" />
<type name=""B"" base=""A<T>"">
<field name=""y1"" type=""A<T>.B"" />
<field name=""y2"" type=""A<D>.B"" />
<type name=""C"" base=""A<T>.B"" />
</type>
<type name=""H"" Of=""S"" base=""System.Object"">
<type name=""I"" base=""A<T>.H<S>"" />
</type>
</type>
<type name=""D"" base=""System.Object"">
<type name=""K"" Of=""T"" base=""System.Object"">
<type name=""L"" base=""D.K<T>"" />
</type>
</type>
<type name=""F"" base=""A<D>"" />
<type name=""G"" base=""A<NS1.E>.B"" />
<type name=""J"" base=""A<D>.H<D>"" />
<type name=""M"" base=""System.Object"" />
<type name=""N"" base=""D.K<M>"" />
<NS1>
<type name=""E"" base=""D"" />
</NS1>
</Global>
", dump);
}, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal));
}
[Fact]
public void StringArrays()
{
string source = @"
public class D
{
public D()
{}
public static void Main()
{
System.Console.WriteLine(65536);
arrayField = new string[] {""string1"", ""string2""};
System.Console.WriteLine(arrayField[1]);
System.Console.WriteLine(arrayField[0]);
}
static string[] arrayField;
}
";
CompileAndVerify(source, expectedOutput: @"
65536
string2
string1
"
);
}
[WorkItem(9229, "DevDiv_Projects/Roslyn")]
[Fact]
public void FieldRVA()
{
string source = @"
public class D
{
public D()
{}
public static void Main()
{
byte[] a = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
System.Console.WriteLine(a[0]);
System.Console.WriteLine(a[8]);
}
}
";
CompileAndVerify(source, expectedOutput: @"
1
9
"
);
}
[Fact]
public void AssemblyRefs1()
{
var metadataTestLib1 = TestReferences.SymbolsTests.MDTestLib1;
var metadataTestLib2 = TestReferences.SymbolsTests.MDTestLib2;
string source = @"
public class Test : C107
{
}
";
CompileAndVerifyWithMscorlib40(source, new[] { metadataTestLib1, metadataTestLib2 }, assemblyValidator: (assembly) =>
{
var refs = assembly.Modules[0].ReferencedAssemblies.OrderBy(r => r.Name).ToArray();
Assert.Equal(2, refs.Length);
Assert.Equal("MDTestLib1", refs[0].Name, StringComparer.OrdinalIgnoreCase);
Assert.Equal("mscorlib", refs[1].Name, StringComparer.OrdinalIgnoreCase);
});
}
[Fact]
public void AssemblyRefs2()
{
string sources = @"
public class Test : Class2
{
}
";
CompileAndVerifyWithMscorlib40(sources, new[] { TestReferences.SymbolsTests.MultiModule.Assembly }, verify: Verification.FailsILVerify, assemblyValidator: (assembly) =>
{
var refs2 = assembly.Modules[0].ReferencedAssemblies.Select(r => r.Name);
Assert.Equal(2, refs2.Count());
Assert.Contains("MultiModule", refs2, StringComparer.OrdinalIgnoreCase);
Assert.Contains("mscorlib", refs2, StringComparer.OrdinalIgnoreCase);
var peFileReader = assembly.GetMetadataReader();
Assert.Equal(0, peFileReader.GetTableRowCount(TableIndex.File));
Assert.Equal(0, peFileReader.GetTableRowCount(TableIndex.ModuleRef));
});
}
[WorkItem(687434, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/687434")]
[Fact()]
public void Bug687434()
{
CompileAndVerify(
"public class C { }",
verify: Verification.Fails,
options: TestOptions.DebugDll.WithOutputKind(OutputKind.NetModule));
}
[Fact, WorkItem(529006, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529006")]
public void AddModule()
{
var netModule1 = ModuleMetadata.CreateFromImage(TestResources.SymbolsTests.netModule.netModule1).GetReference(filePath: Path.GetFullPath("netModule1.netmodule"));
var netModule2 = ModuleMetadata.CreateFromImage(TestResources.SymbolsTests.netModule.netModule2).GetReference(filePath: Path.GetFullPath("netModule2.netmodule"));
string source = @"
public class Test : Class1
{
}
";
// modules not supported in ref emit
// ILVerify: Assembly or module not found: netModule1
CompileAndVerify(source, new[] { netModule1, netModule2 }, verify: Verification.FailsILVerify, assemblyValidator: (assembly) =>
{
Assert.Equal(3, assembly.Modules.Length);
var reader = assembly.GetMetadataReader();
Assert.Equal(2, reader.GetTableRowCount(TableIndex.File));
var file1 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(1));
var file2 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(2));
Assert.Equal("netModule1.netmodule", reader.GetString(file1.Name));
Assert.Equal("netModule2.netmodule", reader.GetString(file2.Name));
Assert.False(file1.HashValue.IsNil);
Assert.False(file2.HashValue.IsNil);
Assert.Equal(1, reader.GetTableRowCount(TableIndex.ModuleRef));
var moduleRefName = reader.GetModuleReference(MetadataTokens.ModuleReferenceHandle(1)).Name;
Assert.Equal("netModule1.netmodule", reader.GetString(moduleRefName));
var actual = from h in reader.ExportedTypes
let et = reader.GetExportedType(h)
select $"{reader.GetString(et.NamespaceDefinition)}.{reader.GetString(et.Name)} 0x{MetadataTokens.GetToken(et.Implementation):X8} ({et.Implementation.Kind}) 0x{(int)et.Attributes:X4}";
AssertEx.Equal(new[]
{
".Class1 0x26000001 (AssemblyFile) 0x0001",
".Class3 0x27000001 (ExportedType) 0x0002",
"NS1.Class4 0x26000001 (AssemblyFile) 0x0001",
".Class7 0x27000003 (ExportedType) 0x0002",
".Class2 0x26000002 (AssemblyFile) 0x0001"
}, actual);
});
}
[Fact]
public void ImplementingAnInterface()
{
string source = @"
public interface I1
{}
public class A : I1
{
}
public interface I2
{
void M2();
}
public interface I3
{
void M3();
}
abstract public class B : I2, I3
{
public abstract void M2();
public abstract void M3();
}
";
CompileAndVerify(source, symbolValidator: module =>
{
var classA = module.GlobalNamespace.GetMember<NamedTypeSymbol>("A");
var classB = module.GlobalNamespace.GetMember<NamedTypeSymbol>("B");
var i1 = module.GlobalNamespace.GetMember<NamedTypeSymbol>("I1");
var i2 = module.GlobalNamespace.GetMember<NamedTypeSymbol>("I2");
var i3 = module.GlobalNamespace.GetMember<NamedTypeSymbol>("I3");
Assert.Equal(TypeKind.Interface, i1.TypeKind);
Assert.Equal(TypeKind.Interface, i2.TypeKind);
Assert.Equal(TypeKind.Interface, i3.TypeKind);
Assert.Equal(TypeKind.Class, classA.TypeKind);
Assert.Equal(TypeKind.Class, classB.TypeKind);
Assert.Same(i1, classA.Interfaces().Single());
var interfaces = classB.Interfaces();
Assert.Same(i2, interfaces[0]);
Assert.Same(i3, interfaces[1]);
Assert.Equal(1, i2.GetMembers("M2").Length);
Assert.Equal(1, i3.GetMembers("M3").Length);
});
}
[Fact]
public void InterfaceOrder()
{
string source = @"
interface I1 : I2, I5 { }
interface I2 : I3, I4 { }
interface I3 { }
interface I4 { }
interface I5 : I6, I7 { }
interface I6 { }
interface I7 { }
class C : I1 { }
";
CompileAndVerify(source, symbolValidator: module =>
{
var i1 = module.GlobalNamespace.GetMember<NamedTypeSymbol>("I1");
var i2 = module.GlobalNamespace.GetMember<NamedTypeSymbol>("I2");
var i3 = module.GlobalNamespace.GetMember<NamedTypeSymbol>("I3");
var i4 = module.GlobalNamespace.GetMember<NamedTypeSymbol>("I4");
var i5 = module.GlobalNamespace.GetMember<NamedTypeSymbol>("I5");
var i6 = module.GlobalNamespace.GetMember<NamedTypeSymbol>("I6");
var i7 = module.GlobalNamespace.GetMember<NamedTypeSymbol>("I7");
var c = module.GlobalNamespace.GetMember<NamedTypeSymbol>("C");
// Order is important - should be pre-order depth-first with declaration order at each level
Assert.True(i1.Interfaces().SequenceEqual(ImmutableArray.Create<NamedTypeSymbol>(i2, i3, i4, i5, i6, i7)));
Assert.True(i2.Interfaces().SequenceEqual(ImmutableArray.Create<NamedTypeSymbol>(i3, i4)));
Assert.False(i3.Interfaces().Any());
Assert.False(i4.Interfaces().Any());
Assert.True(i5.Interfaces().SequenceEqual(ImmutableArray.Create<NamedTypeSymbol>(i6, i7)));
Assert.False(i6.Interfaces().Any());
Assert.False(i7.Interfaces().Any());
Assert.True(c.Interfaces().SequenceEqual(ImmutableArray.Create<NamedTypeSymbol>(i1, i2, i3, i4, i5, i6, i7)));
});
}
[Fact]
public void ExplicitGenericInterfaceImplementation()
{
CompileAndVerify(@"
class S
{
class C<T>
{
public interface I
{
void m(T x);
}
}
abstract public class D : C<int>.I
{
void C<int>.I.m(int x)
{
}
}
}
");
}
[Fact]
public void TypeWithAbstractMethod()
{
string source = @"
abstract public class A
{
public abstract A[] M1(ref System.Array p1);
public abstract A[,] M2(System.Boolean p2);
public abstract A[,,] M3(System.Char p3);
public abstract void M4(System.SByte p4,
System.Single p5,
System.Double p6,
System.Int16 p7,
System.Int32 p8,
System.Int64 p9,
System.IntPtr p10,
System.String p11,
System.Byte p12,
System.UInt16 p13,
System.UInt32 p14,
System.UInt64 p15,
System.UIntPtr p16);
public abstract void M5<T, S>(T p17, S p18);
}";
CompileAndVerify(source, options: TestOptions.ReleaseDll, symbolValidator: module =>
{
var classA = module.GlobalNamespace.GetTypeMembers("A").Single();
var m1 = classA.GetMembers("M1").OfType<MethodSymbol>().Single();
var m2 = classA.GetMembers("M2").OfType<MethodSymbol>().Single();
var m3 = classA.GetMembers("M3").OfType<MethodSymbol>().Single();
var m4 = classA.GetMembers("M4").OfType<MethodSymbol>().Single();
var m5 = classA.GetMembers("M5").OfType<MethodSymbol>().Single();
var method1Ret = (ArrayTypeSymbol)m1.ReturnType;
var method2Ret = (ArrayTypeSymbol)m2.ReturnType;
var method3Ret = (ArrayTypeSymbol)m3.ReturnType;
Assert.True(method1Ret.IsSZArray);
Assert.Same(classA, method1Ret.ElementType);
Assert.Equal(2, method2Ret.Rank);
Assert.Same(classA, method2Ret.ElementType);
Assert.Equal(3, method3Ret.Rank);
Assert.Same(classA, method3Ret.ElementType);
Assert.True(classA.IsAbstract);
Assert.Equal(Accessibility.Public, classA.DeclaredAccessibility);
var parameter1 = m1.Parameters.Single();
var parameter1Type = parameter1.Type;
Assert.Equal(RefKind.Ref, parameter1.RefKind);
Assert.Same(module.GetCorLibType(SpecialType.System_Array), parameter1Type);
Assert.Same(module.GetCorLibType(SpecialType.System_Boolean), m2.Parameters.Single().Type);
Assert.Same(module.GetCorLibType(SpecialType.System_Char), m3.Parameters.Single().Type);
var method4ParamTypes = m4.Parameters.Select(p => p.Type).ToArray();
Assert.Same(module.GetCorLibType(SpecialType.System_Void), m4.ReturnType);
Assert.Same(module.GetCorLibType(SpecialType.System_SByte), method4ParamTypes[0]);
Assert.Same(module.GetCorLibType(SpecialType.System_Single), method4ParamTypes[1]);
Assert.Same(module.GetCorLibType(SpecialType.System_Double), method4ParamTypes[2]);
Assert.Same(module.GetCorLibType(SpecialType.System_Int16), method4ParamTypes[3]);
Assert.Same(module.GetCorLibType(SpecialType.System_Int32), method4ParamTypes[4]);
Assert.Same(module.GetCorLibType(SpecialType.System_Int64), method4ParamTypes[5]);
Assert.Same(module.GetCorLibType(SpecialType.System_IntPtr), method4ParamTypes[6]);
Assert.Same(module.GetCorLibType(SpecialType.System_String), method4ParamTypes[7]);
Assert.Same(module.GetCorLibType(SpecialType.System_Byte), method4ParamTypes[8]);
Assert.Same(module.GetCorLibType(SpecialType.System_UInt16), method4ParamTypes[9]);
Assert.Same(module.GetCorLibType(SpecialType.System_UInt32), method4ParamTypes[10]);
Assert.Same(module.GetCorLibType(SpecialType.System_UInt64), method4ParamTypes[11]);
Assert.Same(module.GetCorLibType(SpecialType.System_UIntPtr), method4ParamTypes[12]);
Assert.True(m5.IsGenericMethod);
Assert.Same(m5.TypeParameters[0], m5.Parameters[0].Type);
Assert.Same(m5.TypeParameters[1], m5.Parameters[1].Type);
Assert.Equal(10, ((PEModuleSymbol)module).Module.GetMetadataReader().TypeReferences.Count);
});
}
[Fact]
public void Types()
{
string source = @"
sealed internal class B
{}
static class C
{
public class D{}
internal class E{}
protected class F{}
private class G{}
protected internal class H{}
class K{}
}
";
Func<bool, Action<ModuleSymbol>> validator = isFromSource => module =>
{
var classB = module.GlobalNamespace.GetTypeMembers("B").Single();
Assert.True(classB.IsSealed);
Assert.Equal(Accessibility.Internal, classB.DeclaredAccessibility);
var classC = module.GlobalNamespace.GetTypeMembers("C").Single();
Assert.True(classC.IsStatic);
Assert.Equal(Accessibility.Internal, classC.DeclaredAccessibility);
var classD = classC.GetTypeMembers("D").Single();
var classE = classC.GetTypeMembers("E").Single();
var classF = classC.GetTypeMembers("F").Single();
var classH = classC.GetTypeMembers("H").Single();
Assert.Equal(Accessibility.Public, classD.DeclaredAccessibility);
Assert.Equal(Accessibility.Internal, classE.DeclaredAccessibility);
Assert.Equal(Accessibility.Protected, classF.DeclaredAccessibility);
Assert.Equal(Accessibility.ProtectedOrInternal, classH.DeclaredAccessibility);
if (isFromSource)
{
var classG = classC.GetTypeMembers("G").Single();
var classK = classC.GetTypeMembers("K").Single();
Assert.Equal(Accessibility.Private, classG.DeclaredAccessibility);
Assert.Equal(Accessibility.Private, classK.DeclaredAccessibility);
}
var peModuleSymbol = module as PEModuleSymbol;
if (peModuleSymbol != null)
{
Assert.Equal(5, peModuleSymbol.Module.GetMetadataReader().TypeReferences.Count);
}
};
CompileAndVerify(source, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.ReleaseDll, sourceSymbolValidator: validator(true), symbolValidator: validator(false));
}
[Fact]
public void Fields()
{
string source = @"
public class A
{
public int F1;
internal volatile int F2;
protected internal string F3;
protected float F4;
private double F5;
char F6;
}";
Func<bool, Action<ModuleSymbol>> validator = isFromSource => module =>
{
var classA = module.GlobalNamespace.GetTypeMembers("A").Single();
var f1 = classA.GetMembers("F1").OfType<FieldSymbol>().Single();
var f2 = classA.GetMembers("F2").OfType<FieldSymbol>().Single();
var f3 = classA.GetMembers("F3").OfType<FieldSymbol>().Single();
var f4 = classA.GetMembers("F4").OfType<FieldSymbol>().Single();
Assert.False(f1.IsVolatile);
Assert.Equal(0, f1.TypeWithAnnotations.CustomModifiers.Length);
Assert.True(f2.IsVolatile);
Assert.Equal(1, f2.TypeWithAnnotations.CustomModifiers.Length);
CustomModifier mod = f2.TypeWithAnnotations.CustomModifiers[0];
Assert.Equal(Accessibility.Public, f1.DeclaredAccessibility);
Assert.Equal(Accessibility.Internal, f2.DeclaredAccessibility);
Assert.Equal(Accessibility.ProtectedOrInternal, f3.DeclaredAccessibility);
Assert.Equal(Accessibility.Protected, f4.DeclaredAccessibility);
if (isFromSource)
{
var f5 = classA.GetMembers("F5").OfType<FieldSymbol>().Single();
var f6 = classA.GetMembers("F6").OfType<FieldSymbol>().Single();
Assert.Equal(Accessibility.Private, f5.DeclaredAccessibility);
Assert.Equal(Accessibility.Private, f6.DeclaredAccessibility);
}
Assert.False(mod.IsOptional);
Assert.Equal("System.Runtime.CompilerServices.IsVolatile", mod.Modifier.ToTestDisplayString());
};
CompileAndVerify(source, sourceSymbolValidator: validator(true), symbolValidator: validator(false), options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal));
}
[Fact]
public void Constructors()
{
string source =
@"namespace N
{
abstract class C
{
static C() {}
protected C() {}
}
}";
Func<bool, Action<ModuleSymbol>> validator = isFromSource => module =>
{
var type = module.GlobalNamespace.GetMember<NamedTypeSymbol>("N.C");
var ctor = (MethodSymbol)type.GetMembers(".ctor").SingleOrDefault();
var cctor = (MethodSymbol)type.GetMembers(".cctor").SingleOrDefault();
Assert.NotNull(ctor);
Assert.Equal(WellKnownMemberNames.InstanceConstructorName, ctor.Name);
Assert.Equal(MethodKind.Constructor, ctor.MethodKind);
Assert.Equal(Accessibility.Protected, ctor.DeclaredAccessibility);
Assert.True(ctor.IsDefinition);
Assert.False(ctor.IsStatic);
Assert.False(ctor.IsAbstract);
Assert.False(ctor.IsSealed);
Assert.False(ctor.IsVirtual);
Assert.False(ctor.IsOverride);
Assert.False(ctor.IsGenericMethod);
Assert.False(ctor.IsExtensionMethod);
Assert.True(ctor.ReturnsVoid);
Assert.False(ctor.IsVararg);
// Bug - 2067
Assert.Equal("N.C." + WellKnownMemberNames.InstanceConstructorName + "()", ctor.ToTestDisplayString());
Assert.Equal(0, ctor.TypeParameters.Length);
Assert.Equal("Void", ctor.ReturnTypeWithAnnotations.Type.Name);
if (isFromSource)
{
Assert.NotNull(cctor);
Assert.Equal(WellKnownMemberNames.StaticConstructorName, cctor.Name);
Assert.Equal(MethodKind.StaticConstructor, cctor.MethodKind);
Assert.Equal(Accessibility.Private, cctor.DeclaredAccessibility);
Assert.True(cctor.IsDefinition);
Assert.True(cctor.IsStatic);
Assert.False(cctor.IsAbstract);
Assert.False(cctor.IsSealed);
Assert.False(cctor.IsVirtual);
Assert.False(cctor.IsOverride);
Assert.False(cctor.IsGenericMethod);
Assert.False(cctor.IsExtensionMethod);
Assert.True(cctor.ReturnsVoid);
Assert.False(cctor.IsVararg);
// Bug - 2067
Assert.Equal("N.C." + WellKnownMemberNames.StaticConstructorName + "()", cctor.ToTestDisplayString());
Assert.Equal(0, cctor.TypeArgumentsWithAnnotations.Length);
Assert.Equal(0, cctor.Parameters.Length);
Assert.Equal("Void", cctor.ReturnTypeWithAnnotations.Type.Name);
}
else
{
Assert.Null(cctor);
}
};
CompileAndVerify(source, sourceSymbolValidator: validator(true), symbolValidator: validator(false));
}
[Fact]
public void ConstantFields()
{
string source =
@"class C
{
private const int I = -1;
internal const int J = I;
protected internal const object O = null;
public const string S = ""string"";
}
";
Func<bool, Action<ModuleSymbol>> validator = isFromSource => module =>
{
var type = module.GlobalNamespace.GetTypeMembers("C").Single();
if (isFromSource)
{
CheckConstantField(type, "I", Accessibility.Private, SpecialType.System_Int32, -1);
}
CheckConstantField(type, "J", Accessibility.Internal, SpecialType.System_Int32, -1);
CheckConstantField(type, "O", Accessibility.ProtectedOrInternal, SpecialType.System_Object, null);
CheckConstantField(type, "S", Accessibility.Public, SpecialType.System_String, "string");
};
CompileAndVerify(source: source, sourceSymbolValidator: validator(true), symbolValidator: validator(false), options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal));
}
private void CheckConstantField(NamedTypeSymbol type, string name, Accessibility declaredAccessibility, SpecialType fieldType, object value)
{
var field = type.GetMembers(name).SingleOrDefault() as FieldSymbol;
Assert.NotNull(field);
Assert.True(field.IsStatic);
Assert.True(field.IsConst);
Assert.Equal(field.DeclaredAccessibility, declaredAccessibility);
Assert.Equal(field.Type.SpecialType, fieldType);
Assert.Equal(field.ConstantValue, value);
}
//the test for not importing internal members is elsewhere
[Fact]
public void DoNotImportPrivateMembers()
{
string source =
@"namespace Namespace
{
public class Public { }
internal class Internal { }
}
class Types
{
public class Public { }
internal class Internal { }
protected class Protected { }
protected internal class ProtectedInternal { }
private class Private { }
}
class Fields
{
public object Public = null;
internal object Internal = null;
protected object Protected = null;
protected internal object ProtectedInternal = null;
private object Private = null;
}
class Methods
{
public void Public() { }
internal void Internal() { }
protected void Protected() { }
protected internal void ProtectedInternal() { }
private void Private() { }
}
class Properties
{
public object Public { get; set; }
internal object Internal { get; set; }
protected object Protected { get; set; }
protected internal object ProtectedInternal { get; set; }
private object Private { get; set; }
}";
Func<bool, Action<ModuleSymbol>> validator = isFromSource => module =>
{
var nmspace = module.GlobalNamespace.GetMember<NamespaceSymbol>("Namespace");
Assert.NotNull(nmspace.GetTypeMembers("Public").SingleOrDefault());
Assert.NotNull(nmspace.GetTypeMembers("Internal").SingleOrDefault());
CheckPrivateMembers(module.GlobalNamespace.GetTypeMembers("Types").Single(), isFromSource, true);
CheckPrivateMembers(module.GlobalNamespace.GetTypeMembers("Fields").Single(), isFromSource, false);
CheckPrivateMembers(module.GlobalNamespace.GetTypeMembers("Methods").Single(), isFromSource, false);
CheckPrivateMembers(module.GlobalNamespace.GetTypeMembers("Properties").Single(), isFromSource, false);
};
CompileAndVerify(source: source, sourceSymbolValidator: validator(true), symbolValidator: validator(false), options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal));
}
private void CheckPrivateMembers(NamedTypeSymbol type, bool isFromSource, bool importPrivates)
{
Symbol member;
member = type.GetMembers("Public").SingleOrDefault();
Assert.NotNull(member);
member = type.GetMembers("Internal").SingleOrDefault();
Assert.NotNull(member);
member = type.GetMembers("Protected").SingleOrDefault();
Assert.NotNull(member);
member = type.GetMembers("ProtectedInternal").SingleOrDefault();
Assert.NotNull(member);
member = type.GetMembers("Private").SingleOrDefault();
if (isFromSource || importPrivates)
{
Assert.NotNull(member);
}
else
{
Assert.Null(member);
}
}
[Fact]
public void GenericBaseTypeResolution()
{
string source =
@"class Base<T, U>
{
}
class Derived<T, U> : Base<T, U>
{
}";
Action<ModuleSymbol> validator = module =>
{
var derivedType = module.GlobalNamespace.GetTypeMembers("Derived").Single();
Assert.Equal(2, derivedType.Arity);
var baseType = derivedType.BaseType();
Assert.Equal("Base", baseType.Name);
Assert.Equal(2, baseType.Arity);
Assert.Equal(derivedType.BaseType(), baseType);
Assert.Same(baseType.TypeArguments()[0], derivedType.TypeParameters[0]);
Assert.Same(baseType.TypeArguments()[1], derivedType.TypeParameters[1]);
};
CompileAndVerify(source: source, sourceSymbolValidator: validator, symbolValidator: validator);
}
[Fact]
public void ImportExplicitImplementations()
{
string source =
@"interface I
{
void Method();
object Property { get; set; }
}
class C : I
{
void I.Method() { }
object I.Property { get; set; }
}";
Action<ModuleSymbol> validator = module =>
{
// Interface
var type = module.GlobalNamespace.GetTypeMembers("I").Single();
var method = (MethodSymbol)type.GetMembers("Method").Single();
Assert.NotNull(method);
var property = (PropertySymbol)type.GetMembers("Property").Single();
Assert.NotNull(property.GetMethod);
Assert.NotNull(property.SetMethod);
// Implementation
type = module.GlobalNamespace.GetTypeMembers("C").Single();
method = (MethodSymbol)type.GetMembers("I.Method").Single();
Assert.NotNull(method);
property = (PropertySymbol)type.GetMembers("I.Property").Single();
Assert.NotNull(property.GetMethod);
Assert.NotNull(property.SetMethod);
};
CompileAndVerify(source: source, sourceSymbolValidator: validator, symbolValidator: validator);
}
[Fact]
public void Properties()
{
string source =
@"public class C
{
public int P1 { get { return 0; } set { } }
internal int P2 { get { return 0; } }
protected internal int P3 { get { return 0; } }
protected int P4 { get { return 0; } }
private int P5 { set { } }
int P6 { get { return 0; } }
public int P7 { private get { return 0; } set { } }
internal int P8 { get { return 0; } private set { } }
protected int P9 { get { return 0; } private set { } }
protected internal int P10 { protected get { return 0; } set { } }
protected internal int P11 { internal get { return 0; } set { } }
}";
Func<bool, Action<ModuleSymbol>> validator = isFromSource => module =>
{
var type = module.GlobalNamespace.GetTypeMembers("C").Single();
var members = type.GetMembers();
// Ensure member names are unique.
var memberNames = members.Select(member => member.Name).Distinct().ToList();
Assert.Equal(memberNames.Count, members.Length);
var c = members.First(member => member.Name == ".ctor");
Assert.NotNull(c);
var p1 = (PropertySymbol)members.First(member => member.Name == "P1");
var p2 = (PropertySymbol)members.First(member => member.Name == "P2");
var p3 = (PropertySymbol)members.First(member => member.Name == "P3");
var p4 = (PropertySymbol)members.First(member => member.Name == "P4");
var p7 = (PropertySymbol)members.First(member => member.Name == "P7");
var p8 = (PropertySymbol)members.First(member => member.Name == "P8");
var p9 = (PropertySymbol)members.First(member => member.Name == "P9");
var p10 = (PropertySymbol)members.First(member => member.Name == "P10");
var p11 = (PropertySymbol)members.First(member => member.Name == "P11");
var privateOrNotApplicable = isFromSource ? Accessibility.Private : Accessibility.NotApplicable;
CheckPropertyAccessibility(p1, Accessibility.Public, Accessibility.Public, Accessibility.Public);
CheckPropertyAccessibility(p2, Accessibility.Internal, Accessibility.Internal, Accessibility.NotApplicable);
CheckPropertyAccessibility(p3, Accessibility.ProtectedOrInternal, Accessibility.ProtectedOrInternal, Accessibility.NotApplicable);
CheckPropertyAccessibility(p4, Accessibility.Protected, Accessibility.Protected, Accessibility.NotApplicable);
CheckPropertyAccessibility(p7, Accessibility.Public, privateOrNotApplicable, Accessibility.Public);
CheckPropertyAccessibility(p8, Accessibility.Internal, Accessibility.Internal, privateOrNotApplicable);
CheckPropertyAccessibility(p9, Accessibility.Protected, Accessibility.Protected, privateOrNotApplicable);
CheckPropertyAccessibility(p10, Accessibility.ProtectedOrInternal, Accessibility.Protected, Accessibility.ProtectedOrInternal);
CheckPropertyAccessibility(p11, Accessibility.ProtectedOrInternal, Accessibility.Internal, Accessibility.ProtectedOrInternal);
if (isFromSource)
{
var p5 = (PropertySymbol)members.First(member => member.Name == "P5");
var p6 = (PropertySymbol)members.First(member => member.Name == "P6");
CheckPropertyAccessibility(p5, Accessibility.Private, Accessibility.NotApplicable, Accessibility.Private);
CheckPropertyAccessibility(p6, Accessibility.Private, Accessibility.Private, Accessibility.NotApplicable);
}
};
CompileAndVerify(source: source, sourceSymbolValidator: validator(true), symbolValidator: validator(false), options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal));
}
[Fact]
public void SetGetOnlyAutopropsInConstructors()
{
var comp = CreateCompilationWithMscorlib461(@"using System;
class C
{
public int P1 { get; }
public static int P2 { get; }
public C()
{
P1 = 10;
}
static C()
{
P2 = 11;
}
static void Main()
{
Console.Write(C.P2);
var c = new C();
Console.Write(c.P1);
}
}", options: TestOptions.DebugExe);
CompileAndVerify(comp, expectedOutput: "1110");
}
[Fact]
public void AutoPropInitializersClass()
{
var comp = CreateCompilation(@"using System;
class C
{
public int P { get; set; } = 1;
public string Q { get; set; } = ""test"";
public decimal R { get; } = 300;
public static char S { get; } = 'S';
static void Main()
{
var c = new C();
Console.Write(c.P);
Console.Write(c.Q);
Console.Write(c.R);
Console.Write(C.S);
}
}", parseOptions: TestOptions.Regular,
options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.Internal));
Action<ModuleSymbol> validator = module =>
{
var type = module.GlobalNamespace.GetMember<NamedTypeSymbol>("C");
var p = type.GetMember<SourcePropertySymbol>("P");
var pBack = p.BackingField;
Assert.False(pBack.IsReadOnly);
Assert.False(pBack.IsStatic);
Assert.Equal(SpecialType.System_Int32, pBack.Type.SpecialType);
var q = type.GetMember<SourcePropertySymbol>("Q");
var qBack = q.BackingField;
Assert.False(qBack.IsReadOnly);
Assert.False(qBack.IsStatic);
Assert.Equal(SpecialType.System_String, qBack.Type.SpecialType);
var r = type.GetMember<SourcePropertySymbol>("R");
var rBack = r.BackingField;
Assert.True(rBack.IsReadOnly);
Assert.False(rBack.IsStatic);
Assert.Equal(SpecialType.System_Decimal, rBack.Type.SpecialType);
var s = type.GetMember<SourcePropertySymbol>("S");
var sBack = s.BackingField;
Assert.True(sBack.IsReadOnly);
Assert.True(sBack.IsStatic);
Assert.Equal(SpecialType.System_Char, sBack.Type.SpecialType);
};
CompileAndVerify(
comp,
sourceSymbolValidator: validator,
expectedOutput: "1test300S");
}
[Fact]
public void AutoPropInitializersStruct()
{
var comp = CreateCompilation(@"
using System;
struct S
{
public readonly int P;
public string Q { get; }
public decimal R { get; }
public static char T { get; } = 'T';
public S(int p)
{
P = p;
Q = ""test"";
R = 300;
}
static void Main()
{
var s = new S(1);
Console.Write(s.P);
Console.Write(s.Q);
Console.Write(s.R);
Console.Write(S.T);
s = new S();
Console.Write(s.P);
Console.Write(s.Q ?? ""null"");
Console.Write(s.R);
Console.Write(S.T);
}
}", parseOptions: TestOptions.Regular,
options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.Internal));
Action<ModuleSymbol> validator = module =>
{
var type = module.GlobalNamespace.GetMember<NamedTypeSymbol>("S");
var p = type.GetMember<SourceMemberFieldSymbol>("P");
Assert.False(p.HasInitializer);
Assert.True(p.IsReadOnly);
Assert.False(p.IsStatic);
Assert.Equal(SpecialType.System_Int32, p.Type.SpecialType);
var q = type.GetMember<SourcePropertySymbol>("Q");
var qBack = q.BackingField;
Assert.True(qBack.IsReadOnly);
Assert.False(qBack.IsStatic);
Assert.Equal(SpecialType.System_String, qBack.Type.SpecialType);
var r = type.GetMember<SourcePropertySymbol>("R");
var rBack = r.BackingField;
Assert.True(rBack.IsReadOnly);
Assert.False(rBack.IsStatic);
Assert.Equal(SpecialType.System_Decimal, rBack.Type.SpecialType);
var s = type.GetMember<SourcePropertySymbol>("T");
var sBack = s.BackingField;
Assert.True(sBack.IsReadOnly);
Assert.True(sBack.IsStatic);
Assert.Equal(SpecialType.System_Char, sBack.Type.SpecialType);
};
CompileAndVerify(
comp,
sourceSymbolValidator: validator,
expectedOutput: "1test300T0null0T");
}
/// <summary>
/// Private accessors of a virtual property should not be virtual.
/// </summary>
[Fact]
public void PrivatePropertyAccessorNotVirtual()
{
string source = @"
class C
{
public virtual int P { get; private set; }
public virtual int Q { get; internal set; }
}
class D : C
{
public override int Q { internal set { } }
}
class E : D
{
public override int Q { get { return 0; } }
}
class F : E
{
public override int P { get { return 0; } }
public override int Q { internal set { } }
}
class Program
{
static void Main()
{
}
}
";
Func<bool, Action<ModuleSymbol>> validator = isFromSource => module =>
{
var type = module.GlobalNamespace.GetTypeMembers("C").Single();
bool checkValidProperties = (type is PENamedTypeSymbol);
var propertyP = (PropertySymbol)type.GetMembers("P").Single();
if (isFromSource)
{
CheckPropertyAccessibility(propertyP, Accessibility.Public, Accessibility.Public, Accessibility.Private);
Assert.False(propertyP.SetMethod.IsVirtual);
Assert.False(propertyP.SetMethod.IsOverride);
}
else
{
CheckPropertyAccessibility(propertyP, Accessibility.Public, Accessibility.Public, Accessibility.NotApplicable);
Assert.Null(propertyP.SetMethod);
}
Assert.True(propertyP.GetMethod.IsVirtual);
Assert.False(propertyP.GetMethod.IsOverride);
var propertyQ = (PropertySymbol)type.GetMembers("Q").Single();
CheckPropertyAccessibility(propertyQ, Accessibility.Public, Accessibility.Public, Accessibility.Internal);
Assert.True(propertyQ.GetMethod.IsVirtual);
Assert.False(propertyQ.GetMethod.IsOverride);
Assert.True(propertyQ.SetMethod.IsVirtual);
Assert.False(propertyQ.SetMethod.IsOverride);
Assert.False(propertyQ.IsReadOnly);
Assert.False(propertyQ.IsWriteOnly);
if (checkValidProperties)
{
Assert.False(propertyP.MustCallMethodsDirectly);
Assert.False(propertyQ.MustCallMethodsDirectly);
}
type = module.GlobalNamespace.GetTypeMembers("F").Single();
propertyP = (PropertySymbol)type.GetMembers("P").Single();
CheckPropertyAccessibility(propertyP, Accessibility.Public, Accessibility.Public, Accessibility.NotApplicable);
Assert.False(propertyP.GetMethod.IsVirtual);
Assert.True(propertyP.GetMethod.IsOverride);
propertyQ = (PropertySymbol)type.GetMembers("Q").Single();
// Derived property should be public even though the only
// declared accessor on the derived property is internal.
CheckPropertyAccessibility(propertyQ, Accessibility.Public, Accessibility.NotApplicable, Accessibility.Internal);
Assert.False(propertyQ.SetMethod.IsVirtual);
Assert.True(propertyQ.SetMethod.IsOverride);
Assert.False(propertyQ.IsReadOnly);
Assert.False(propertyQ.IsWriteOnly);
if (checkValidProperties)
{
Assert.False(propertyP.MustCallMethodsDirectly);
Assert.False(propertyQ.MustCallMethodsDirectly);
}
// Overridden property should be E but overridden
// accessor should be D.set_Q.
var overriddenProperty = module.GlobalNamespace.GetTypeMembers("E").Single().GetMembers("Q").Single();
Assert.NotNull(overriddenProperty);
Assert.Same(overriddenProperty, propertyQ.OverriddenProperty);
var overriddenAccessor = module.GlobalNamespace.GetTypeMembers("D").Single().GetMembers("set_Q").Single();
Assert.NotNull(overriddenProperty);
Assert.Same(overriddenAccessor, propertyQ.SetMethod.OverriddenMethod);
};
CompileAndVerify(source: source, sourceSymbolValidator: validator(true), symbolValidator: validator(false));
}
[Fact]
public void InterfaceProperties()
{
string source = @"
interface I
{
int P { get; set; }
}
public class C : I
{
int I.P { get { return 0; } set { } }
}";
Action<ModuleSymbol> validator = module =>
{
var type = module.GlobalNamespace.GetTypeMembers("C").Single();
var members = type.GetMembers();
var ip = (PropertySymbol)members.First(member => member.Name == "I.P");
CheckPropertyAccessibility(ip, Accessibility.Private, Accessibility.Private, Accessibility.Private);
};
CompileAndVerify(source: source, sourceSymbolValidator: validator, symbolValidator: validator);
}
private static void CheckPropertyAccessibility(PropertySymbol property, Accessibility propertyAccessibility, Accessibility getterAccessibility, Accessibility setterAccessibility)
{
var type = property.TypeWithAnnotations;
Assert.NotEqual(Microsoft.Cci.PrimitiveTypeCode.Void, type.PrimitiveTypeCode);
Assert.Equal(propertyAccessibility, property.DeclaredAccessibility);
CheckPropertyAccessorAccessibility(property, propertyAccessibility, property.GetMethod, getterAccessibility);
CheckPropertyAccessorAccessibility(property, propertyAccessibility, property.SetMethod, setterAccessibility);
}
private static void CheckPropertyAccessorAccessibility(PropertySymbol property, Accessibility propertyAccessibility, MethodSymbol accessor, Accessibility accessorAccessibility)
{
if (accessor == null)
{
Assert.Equal(Accessibility.NotApplicable, accessorAccessibility);
}
else
{
var containingType = property.ContainingType;
Assert.Equal(property, accessor.AssociatedSymbol);
Assert.Equal(containingType, accessor.ContainingType);
Assert.Equal(containingType, accessor.ContainingSymbol);
var method = containingType.GetMembers(accessor.Name).Single();
Assert.Equal(method, accessor);
Assert.Equal(accessorAccessibility, accessor.DeclaredAccessibility);
}
}
// Property/method override should succeed (and should reference
// the correct base method, even if there is a method/property
// with the same name in an intermediate class.
[WorkItem(538720, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538720")]
[Fact]
public void TestPropertyOverrideGet()
{
PropertyOverrideGet(@"
class A
{
public virtual int P { get { return 0; } }
}
class B : A
{
public virtual int get_P() { return 0; }
}
class C : B
{
public override int P { get { return 0; } }
}
");
PropertyOverrideGet(@"
class A
{
public virtual int get_P() { return 0; }
}
class B : A
{
public virtual int P { get { return 0; } }
}
class C : B
{
public override int get_P() { return 0; }
}
");
}
private void PropertyOverrideGet(string source)
{
Action<ModuleSymbol> validator = module =>
{
var typeA = module.GlobalNamespace.GetTypeMembers("A").Single();
Assert.NotNull(typeA);
var getMethodA = (MethodSymbol)typeA.GetMembers("get_P").Single();
Assert.NotNull(getMethodA);
Assert.True(getMethodA.IsVirtual);
Assert.False(getMethodA.IsOverride);
var typeC = module.GlobalNamespace.GetTypeMembers("C").Single();
Assert.NotNull(typeC);
var getMethodC = (MethodSymbol)typeC.GetMembers("get_P").Single();
Assert.NotNull(getMethodC);
Assert.False(getMethodC.IsVirtual);
Assert.True(getMethodC.IsOverride);
Assert.Same(getMethodC.OverriddenMethod, getMethodA);
};
CompileAndVerify(source: source, sourceSymbolValidator: validator, symbolValidator: validator);
}
[Fact]
public void AutoProperties()
{
string source = @"
class A
{
public int P { get; private set; }
internal int Q { get; set; }
}
class B<T>
{
protected internal T P { get; set; }
}
class C : B<string>
{
}
";
Func<bool, Action<ModuleSymbol>> validator = isFromSource => module =>
{
var classA = module.GlobalNamespace.GetTypeMember("A");
var p = classA.GetProperty("P");
VerifyAutoProperty(p, isFromSource);
var q = classA.GetProperty("Q");
VerifyAutoProperty(q, isFromSource);
var classC = module.GlobalNamespace.GetTypeMembers("C").Single();
p = classC.BaseType().GetProperty("P");
VerifyAutoProperty(p, isFromSource);
Assert.Equal(SpecialType.System_String, p.Type.SpecialType);
Assert.Equal(p.GetMethod.AssociatedSymbol, p);
};
CompileAndVerify(
source,
sourceSymbolValidator: validator(true),
symbolValidator: validator(false),
options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All));
}
private static void VerifyAutoProperty(PropertySymbol property, bool isFromSource)
{
if (isFromSource)
{
if (property is SourcePropertySymbol sourceProperty)
{
Assert.True(sourceProperty.IsAutoProperty);
}
}
else
{
var backingField = property.ContainingType.GetField(GeneratedNames.MakeBackingFieldName(property.Name));
var attribute = backingField.GetAttributes().Single();
Assert.Equal("System.Runtime.CompilerServices.CompilerGeneratedAttribute", attribute.AttributeClass.ToTestDisplayString());
Assert.Empty(attribute.AttributeConstructor.Parameters);
}
VerifyAutoPropertyAccessor(property, property.GetMethod);
VerifyAutoPropertyAccessor(property, property.SetMethod);
}
private static void VerifyAutoPropertyAccessor(PropertySymbol property, MethodSymbol accessor)
{
if (accessor != null)
{
var method = property.ContainingType.GetMembers(accessor.Name).Single();
Assert.Equal(method, accessor);
Assert.Equal(accessor.AssociatedSymbol, property);
Assert.False(accessor.IsImplicitlyDeclared, "MethodSymbol.IsImplicitlyDeclared should be false for auto property accessors");
}
}
[Fact]
public void EmptyEnum()
{
string source = "enum E {}";
Action<ModuleSymbol> validator = module =>
{
var type = module.GlobalNamespace.GetTypeMembers("E").Single();
CheckEnumType(type, Accessibility.Internal, SpecialType.System_Int32);
Assert.Equal(1, type.GetMembers().Length);
};
CompileAndVerify(source: source, sourceSymbolValidator: validator, symbolValidator: validator);
}
[Fact]
public void NonEmptyEnum()
{
string source =
@"enum E : short
{
A,
B = 0x02,
C,
D,
E = B | D,
F = C,
G,
}
";
Action<ModuleSymbol> validator = module =>
{
var type = module.GlobalNamespace.GetTypeMembers("E").Single();
CheckEnumType(type, Accessibility.Internal, SpecialType.System_Int16);
Assert.Equal(8, type.GetMembers().Length);
CheckEnumConstant(type, "A", (short)0);
CheckEnumConstant(type, "B", (short)2);
CheckEnumConstant(type, "C", (short)3);
CheckEnumConstant(type, "D", (short)4);
CheckEnumConstant(type, "E", (short)6);
CheckEnumConstant(type, "F", (short)3);
CheckEnumConstant(type, "G", (short)4);
};
CompileAndVerify(source: source, sourceSymbolValidator: validator, symbolValidator: validator);
}
private void CheckEnumConstant(NamedTypeSymbol type, string name, object value)
{
var field = type.GetMembers(name).SingleOrDefault() as FieldSymbol;
Assert.NotNull(field);
Assert.True(field.IsStatic);
Assert.True(field.IsConst);
// TODO: DeclaredAccessibility should be NotApplicable.
//Assert.Equal(field.DeclaredAccessibility, Accessibility.NotApplicable);
Assert.Equal(field.Type, type);
Assert.Equal(field.ConstantValue, value);
var sourceType = type as SourceNamedTypeSymbol;
if ((object)sourceType != null)
{
var fieldDefinition = (Microsoft.Cci.IFieldDefinition)field.GetCciAdapter();
Assert.False(fieldDefinition.IsSpecialName);
Assert.False(fieldDefinition.IsRuntimeSpecial);
}
}
private void CheckEnumType(NamedTypeSymbol type, Accessibility declaredAccessibility, SpecialType underlyingType)
{
Assert.Equal(SpecialType.System_Enum, type.BaseType().SpecialType);
Assert.Equal(type.EnumUnderlyingType.SpecialType, underlyingType);
Assert.Equal(type.DeclaredAccessibility, declaredAccessibility);
Assert.True(type.IsSealed);
// value__ field should not be exposed from type, even though it is public,
// since we want to prevent source from accessing the field directly.
var field = type.GetMembers(WellKnownMemberNames.EnumBackingFieldName).SingleOrDefault() as FieldSymbol;
Assert.Null(field);
var sourceType = type as SourceNamedTypeSymbol;
if ((object)sourceType != null)
{
field = sourceType.EnumValueField;
Assert.NotNull(field);
Assert.Equal(WellKnownMemberNames.EnumBackingFieldName, field.Name);
Assert.False(field.IsStatic);
Assert.False(field.IsConst);
Assert.False(field.IsReadOnly);
Assert.Equal(Accessibility.Public, field.DeclaredAccessibility); // Dev10: value__ is public
Assert.Equal(field.Type, type.EnumUnderlyingType);
var module = new PEAssemblyBuilder((SourceAssemblySymbol)sourceType.ContainingAssembly, EmitOptions.Default, OutputKind.DynamicallyLinkedLibrary,
GetDefaultModulePropertiesForSerialization(), SpecializedCollections.EmptyEnumerable<ResourceDescription>());
var context = new EmitContext(module, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true);
var typeDefinition = (Microsoft.Cci.ITypeDefinition)type.GetCciAdapter();
var fieldDefinition = typeDefinition.GetFields(context).First();
Assert.Same(fieldDefinition.GetInternalSymbol(), field); // Dev10: value__ field is the first field.
Assert.True(fieldDefinition.IsSpecialName);
Assert.True(fieldDefinition.IsRuntimeSpecial);
context.Diagnostics.Verify();
}
}
[Fact]
public void GenericMethods()
{
string source = @"
public class A
{
public static void Main()
{
System.Console.WriteLine(""GenericMethods"");
//B.Test<int>();
//C<int>.Test<int>();
}
}
public class B
{
public static void Test<T>()
{
System.Console.WriteLine(""Test<T>"");
}
}
public class C<T>
{
public static void Test<S>()
{
System.Console.WriteLine(""C<T>.Test<S>"");
}
}
";
CompileAndVerify(source, expectedOutput: "GenericMethods\r\n");
}
[Fact]
public void GenericMethods2()
{
string source = @"
class A
{
public static void Main()
{
TC1 x = new TC1();
System.Console.WriteLine(x.GetType());
TC2<byte> y = new TC2<byte>();
System.Console.WriteLine(y.GetType());
TC3<byte>.TC4 z = new TC3<byte>.TC4();
System.Console.WriteLine(z.GetType());
}
}
class TC1
{
void TM1<T1>()
{
TM1<T1>();
}
void TM2<T2>()
{
TM2<int>();
}
}
class TC2<T3>
{
void TM3<T4>()
{
TM3<T4>();
TM3<T4>();
}
void TM4<T5>()
{
TM4<int>();
TM4<int>();
}
static void TM5<T6>(T6 x)
{
TC2<int>.TM5(x);
}
static void TM6<T7>(T7 x)
{
TC2<int>.TM6(1);
}
void TM9()
{
TM9();
TM9();
}
}
class TC3<T8>
{
public class TC4
{
void TM7<T9>()
{
TM7<T9>();
TM7<int>();
}
static void TM8<T10>(T10 x)
{
TC3<int>.TC4.TM8(x);
TC3<int>.TC4.TM8(1);
}
}
}
";
var verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput:
@"TC1
TC2`1[System.Byte]
TC3`1+TC4[System.Byte]
");
verifier.VerifyIL("TC1.TM1<T1>",
@"{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""void TC1.TM1<T1>()""
IL_0006: ret
}
");
verifier.VerifyIL("TC1.TM2<T2>",
@"{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""void TC1.TM2<int>()""
IL_0006: ret
}
");
verifier.VerifyIL("TC2<T3>.TM3<T4>",
@"{
// Code size 13 (0xd)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""void TC2<T3>.TM3<T4>()""
IL_0006: ldarg.0
IL_0007: call ""void TC2<T3>.TM3<T4>()""
IL_000c: ret
}
");
verifier.VerifyIL("TC2<T3>.TM4<T5>",
@"{
// Code size 13 (0xd)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""void TC2<T3>.TM4<int>()""
IL_0006: ldarg.0
IL_0007: call ""void TC2<T3>.TM4<int>()""
IL_000c: ret
}
");
verifier.VerifyIL("TC2<T3>.TM5<T6>",
@"{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""void TC2<int>.TM5<T6>(T6)""
IL_0006: ret
}
");
verifier.VerifyIL("TC2<T3>.TM6<T7>",
@"{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldc.i4.1
IL_0001: call ""void TC2<int>.TM6<int>(int)""
IL_0006: ret
}
");
}
[Fact]
public void Generics3()
{
string source = @"
using System;
class Program
{
static void Main(string[] args)
{
C1<Byte, Byte> x1 = new C1<Byte, Byte>();
C1<Byte, Byte>.C2<Byte, Byte> x2 = new C1<Byte, Byte>.C2<Byte, Byte>();
C1<Byte, Byte>.C2<Byte, Byte>.C3<Byte, Byte> x3 = new C1<Byte, Byte>.C2<Byte, Byte>.C3<Byte, Byte>();
C1<Byte, Byte>.C2<Byte, Byte>.C3<Byte, Byte>.C4<Byte> x4 = new C1<Byte, Byte>.C2<Byte, Byte>.C3<Byte, Byte>.C4<Byte>();
C1<Byte, Byte>.C5 x5 = new C1<Byte, Byte>.C5();
}
}
class C1<C1T1, C1T2>
{
public class C2<C2T1, C2T2>
{
public class C3<C3T1, C3T2> where C3T2 : C1T1
{
public class C4<C4T1>
{
}
}
public C1<int, C2T2>.C5 V1;
public C1<C2T1, C2T2>.C5 V2;
public C1<int, int>.C5 V3;
public C2<Byte, Byte> V4;
public C1<C1T2, C1T1>.C2<C2T1, C2T2> V5;
public C1<C1T2, C1T1>.C2<C2T2, C2T1> V6;
public C1<C1T2, C1T1>.C2<Byte, int> V7;
public C2<C2T1, C2T2> V8;
public C2<Byte, C2T2> V9;
void Test12(C2<int, int> x)
{
C1<C1T1, C1T2>.C2<Byte, int> y = x.V9;
}
void Test11(C1<int, int>.C2<Byte, Byte> x)
{
C1<int, int>.C2<Byte, Byte> y = x.V8;
}
void Test6(C1<C1T2, C1T1>.C2<C2T1, C2T2> x)
{
C1<C1T1, C1T2>.C2<C2T1, C2T2> y = x.V5;
}
void Test7(C1<C1T2, C1T1>.C2<C2T2, C2T1> x)
{
C1<C1T1, C1T2>.C2<C2T1, C2T2> y = x.V6;
}
void Test8(C1<C1T2, C1T1>.C2<C2T2, C2T1> x)
{
C1<C1T1, C1T2>.C2<Byte, int> y = x.V7;
}
void Test9(C1<int, Byte>.C2<C2T2, C2T1> x)
{
C1<Byte, int>.C2<Byte, int> y = x.V7;
}
void Test10(C1<C1T1, C1T2>.C2<C2T2, C2T1> x)
{
C1<C1T2, C1T1>.C2<Byte, int> y = x.V7;
}
}
public class C5
{
}
void Test1(C2<C1T1, int> x)
{
C1<int, int>.C5 y = x.V1;
}
void Test2(C2<C1T1, C1T2> x)
{
C5 y = x.V2;
}
void Test3(C2<C1T2, C1T1> x)
{
C1<int, int>.C5 y = x.V3;
}
void Test4(C1<int, int>.C2<C1T1, C1T2> x)
{
C1<int, int>.C2<Byte, Byte> y = x.V4;
}
}
";
CompileAndVerify(source);
}
[Fact]
public void RefEmit_UnsupportedOrdering1()
{
CompileAndVerify(@"
public class E
{
public struct N2
{
public N3 n1;
}
public struct N3
{
}
N2 n2;
}
");
}
[Fact]
public void RefEmit_UnsupportedOrdering1_EP()
{
string source = @"
public class E
{
public struct N2
{
public N3 n1;
}
public struct N3
{
}
N2 n2;
public static void Main()
{
System.Console.Write(1234);
}
}";
CompileAndVerify(source, expectedOutput: @"1234");
}
[Fact]
public void RefEmit_UnsupportedOrdering2()
{
CompileAndVerify(@"
class B<T> where T : A {}
class A : B<A> {}
");
}
[Fact]
public void RefEmit_MembersOfOpenGenericType()
{
CompileAndVerify(@"
class C<T>
{
void goo()
{
System.Collections.Generic.Dictionary<int, T> d = new System.Collections.Generic.Dictionary<int, T>();
}
}
");
}
[Fact]
public void RefEmit_ListOfValueTypes()
{
string source = @"
using System.Collections.Generic;
class A
{
struct S { }
List<S> f;
}";
CompileAndVerify(source);
}
[Fact]
public void RefEmit_SpecializedNestedSelfReference()
{
string source = @"
class A<T>
{
class B {
}
A<int>.B x;
}";
CompileAndVerify(source);
}
[Fact]
public void RefEmit_SpecializedNestedGenericSelfReference()
{
string source = @"
class A<T>
{
public class B<S> {
public class C<U,V> {
}
}
A<int>.B<double>.C<string, bool> x;
}";
CompileAndVerify(source);
}
[Fact]
public void RefEmit_Cycle()
{
string source = @"
public class B : I<C> { }
public class C : I<B> { }
public interface I<T> { }
";
CompileAndVerify(source);
}
[Fact]
public void RefEmit_SpecializedMemberReference()
{
string source = @"
class A<T>
{
public A()
{
A<int>.method();
int a = A<string>.field;
new A<double>();
}
public static void method()
{
}
public static int field;
}";
CompileAndVerify(source);
}
[Fact]
public void RefEmit_NestedGenericTypeReferences()
{
string source = @"
class A<T>
{
public class H<S>
{
A<T>.H<S> x;
}
}";
CompileAndVerify(source);
}
[Fact]
public void RefEmit_Ordering2()
{
// order:
// E <(value type field) E.C.N2 <(value type field) N3
string source = @"
public class E
{
public class C {
public struct N2
{
public N3 n1;
}
}
C.N2 n2;
}
public struct N3
{
E f;
int g;
}";
CompileAndVerify(source);
}
[Fact]
public void RefEmit_Ordering3()
{
string source = @"
using System.Collections.Generic;
public class E
{
public struct N2
{
public List<N3> n1; // E.N2 doesn't depend on E.N3 since List<> isn't a value type
}
public struct N3
{
}
N2 n2;
}";
CompileAndVerify(source);
}
[Fact]
public void RefEmit_IL1()
{
CompileAndVerify(@"
using System.Globalization;
class C
{
public static void Main()
{
int i = 0, j, k = 2147483647;
long l = 0, m = 9200000000000000000L;
int b = -10;
byte c = 200;
float f = 3.14159F;
double d = 2.71828;
string s = ""abcdef"";
bool x = true;
System.Console.WriteLine(i);
System.Console.WriteLine(k);
System.Console.WriteLine(b);
System.Console.WriteLine(c);
System.Console.WriteLine(f.ToString(CultureInfo.InvariantCulture));
System.Console.WriteLine(d.ToString(CultureInfo.InvariantCulture));
System.Console.WriteLine(s);
System.Console.WriteLine(x);
}
}
", expectedOutput: @"
0
2147483647
-10
200
3.14159
2.71828
abcdef
True
");
}
[WorkItem(540581, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540581")]
[Fact]
public void RefEmit_DependencyGraphAndCachedTypeReferences()
{
var source = @"
using System;
interface I1<T>
{
void Method(T x);
}
interface I2<U>
{
void Method(U x);
}
interface I3<W> : I1<W>, I2<W>
{
void Method(W x);
}
class Implicit2 : I3<string> // Implicit2 depends on I3<string>
{
public void Method(string x) { }
}
class Test
{
public static void Main()
{
I3<string> i = new Implicit2();
}
}
";
// If I3<string> in Main body is resolved first and stored in a cache,
// the fact that Implicit2 depends on I3<string> isn't recorded if we pull
// I3<string> from cache at the beginning of ResolveType method.
CompileAndVerify(source);
}
[Fact]
public void CheckRef()
{
string source = @"
public abstract class C
{
public abstract int M(int x, ref int y, out int z);
}
";
CompileAndVerify(source, symbolValidator: module =>
{
var global = module.GlobalNamespace;
var c = global.GetTypeMembers("C", 0).Single() as NamedTypeSymbol;
var m = c.GetMembers("M").Single() as MethodSymbol;
Assert.Equal(RefKind.None, m.Parameters[0].RefKind);
Assert.Equal(RefKind.Ref, m.Parameters[1].RefKind);
Assert.Equal(RefKind.Out, m.Parameters[2].RefKind);
});
}
[Fact]
public void OutArgument()
{
string source = @"
class C
{
static void Main() { double d; double.TryParse(null, out d); }
}
";
CompileAndVerify(source);
}
[Fact]
public void CreateInstance()
{
string source = @"
class C
{
static void Main() { System.Activator.CreateInstance<int>(); }
}
";
CompileAndVerify(source);
}
[Fact]
public void DelegateRoundTrip()
{
string source = @"delegate int MyDel(
int x,
// ref int y, // commented out until 4264 is fixed.
// out int z, // commented out until 4264 is fixed.
int w);";
CompileAndVerify(source, symbolValidator: module =>
{
var global = module.GlobalNamespace;
var myDel = global.GetTypeMembers("MyDel", 0).Single() as NamedTypeSymbol;
var invoke = myDel.DelegateInvokeMethod;
var beginInvoke = myDel.GetMembers("BeginInvoke").Single() as MethodSymbol;
Assert.Equal(invoke.Parameters.Length + 2, beginInvoke.Parameters.Length);
Assert.Equal(TypeKind.Interface, beginInvoke.ReturnType.TypeKind);
Assert.Equal("System.IAsyncResult", beginInvoke.ReturnType.ToTestDisplayString());
for (int i = 0; i < invoke.Parameters.Length; i++)
{
Assert.Equal(invoke.Parameters[i].Type, beginInvoke.Parameters[i].Type);
Assert.Equal(invoke.Parameters[i].RefKind, beginInvoke.Parameters[i].RefKind);
}
Assert.Equal("System.AsyncCallback", beginInvoke.Parameters[invoke.Parameters.Length].Type.ToTestDisplayString());
Assert.Equal("System.Object", beginInvoke.Parameters[invoke.Parameters.Length + 1].Type.ToTestDisplayString());
var invokeReturn = invoke.ReturnType;
var endInvoke = myDel.GetMembers("EndInvoke").Single() as MethodSymbol;
var endInvokeReturn = endInvoke.ReturnType;
Assert.Equal(invokeReturn, endInvokeReturn);
int k = 0;
for (int i = 0; i < invoke.Parameters.Length; i++)
{
if (invoke.Parameters[i].RefKind != RefKind.None)
{
Assert.Equal(invoke.Parameters[i].TypeWithAnnotations, endInvoke.Parameters[k].TypeWithAnnotations);
Assert.Equal(invoke.Parameters[i].RefKind, endInvoke.Parameters[k++].RefKind);
}
}
Assert.Equal("System.IAsyncResult", endInvoke.Parameters[k++].Type.ToTestDisplayString());
Assert.Equal(k, endInvoke.Parameters.Length);
});
}
[Fact]
public void StaticClassRoundTrip()
{
string source = @"
public static class C
{
private static string msg = ""Hello"";
private static void Goo()
{
System.Console.WriteLine(msg);
}
public static void Main()
{
Goo();
}
}
";
CompileAndVerify(source,
symbolValidator: module =>
{
var global = module.GlobalNamespace;
var classC = global.GetMember<NamedTypeSymbol>("C");
Assert.True(classC.IsStatic, "Expected C to be static");
Assert.False(classC.IsAbstract, "Expected C to be non-abstract"); //even though it is abstract in metadata
Assert.False(classC.IsSealed, "Expected C to be non-sealed"); //even though it is sealed in metadata
Assert.Equal(0, classC.GetMembers(WellKnownMemberNames.InstanceConstructorName).Length); //since C is static
Assert.Equal(0, classC.GetMembers(WellKnownMemberNames.StaticConstructorName).Length); //since we don't import private members
});
}
[Fact]
public void DoNotImportInternalMembers()
{
string sources =
@"public class Fields
{
public int Public;
internal int Internal;
}
public class Methods
{
public void Public() {}
internal void Internal() {}
}";
Func<bool, Action<ModuleSymbol>> validator = isFromSource => (ModuleSymbol m) =>
{
CheckInternalMembers(m.GlobalNamespace.GetTypeMembers("Fields").Single(), isFromSource);
CheckInternalMembers(m.GlobalNamespace.GetTypeMembers("Methods").Single(), isFromSource);
};
CompileAndVerify(sources, sourceSymbolValidator: validator(true), symbolValidator: validator(false));
}
[Fact]
public void Issue4695()
{
string source = @"
using System;
class Program
{
sealed class Cache
{
abstract class BucketwiseBase<TArg> where TArg : class
{
internal abstract void Default(TArg arg);
}
class BucketwiseBase<TAccumulator, TArg> : BucketwiseBase<TArg> where TArg : class
{
internal override void Default(TArg arg = null) { }
}
public string GetAll()
{
new BucketwiseBase<object, object>().Default(); // Bad image format thrown here on legacy compiler
return ""OK"";
}
}
static void Main(string[] args)
{
Console.WriteLine(new Cache().GetAll());
}
}
";
CompileAndVerify(source, expectedOutput: "OK");
}
private void CheckInternalMembers(NamedTypeSymbol type, bool isFromSource)
{
Assert.NotNull(type.GetMembers("Public").SingleOrDefault());
var member = type.GetMembers("Internal").SingleOrDefault();
if (isFromSource)
Assert.NotNull(member);
else
Assert.Null(member);
}
[WorkItem(90, "https://github.com/dotnet/roslyn/issues/90")]
[Fact]
public void EmitWithNoResourcesAllPlatforms()
{
var comp = CreateCompilation("class Test { static void Main() { } }");
VerifyEmitWithNoResources(comp, Platform.AnyCpu);
VerifyEmitWithNoResources(comp, Platform.AnyCpu32BitPreferred);
VerifyEmitWithNoResources(comp, Platform.Arm); // broken before fix
VerifyEmitWithNoResources(comp, Platform.Itanium); // broken before fix
VerifyEmitWithNoResources(comp, Platform.X64); // broken before fix
VerifyEmitWithNoResources(comp, Platform.X86);
}
private void VerifyEmitWithNoResources(CSharpCompilation comp, Platform platform)
{
var options = TestOptions.ReleaseExe.WithPlatform(platform);
CompileAndVerify(comp.WithAssemblyName("EmitWithNoResourcesAllPlatforms_" + platform.ToString()).WithOptions(options));
}
[Fact]
public unsafe void PEHeaders1()
{
var options = EmitOptions.Default.WithFileAlignment(0x2000);
var syntax = SyntaxFactory.ParseSyntaxTree(@"class C {}", TestOptions.Regular.WithNoRefSafetyRulesAttribute());
var peStream = CreateCompilationWithMscorlib40(
syntax,
options: TestOptions.ReleaseDll.WithDeterministic(true),
assemblyName: "46B9C2B2-B7A0-45C5-9EF9-28DDF739FD9E").EmitToStream(options);
peStream.Position = 0;
var peReader = new PEReader(peStream);
var peHeaders = peReader.PEHeaders;
var peHeader = peHeaders.PEHeader;
var coffHeader = peHeaders.CoffHeader;
var corHeader = peHeaders.CorHeader;
Assert.Equal(PEMagic.PE32, peHeader.Magic);
Assert.Equal(0x0000237E, peHeader.AddressOfEntryPoint);
Assert.Equal(0x00002000, peHeader.BaseOfCode);
Assert.Equal(0x00004000, peHeader.BaseOfData);
Assert.Equal(0x00002000, peHeader.SizeOfHeaders);
Assert.Equal(0x00002000, peHeader.SizeOfCode);
Assert.Equal(0x00001000u, peHeader.SizeOfHeapCommit);
Assert.Equal(0x00100000u, peHeader.SizeOfHeapReserve);
Assert.Equal(0x00006000, peHeader.SizeOfImage);
Assert.Equal(0x00002000, peHeader.SizeOfInitializedData);
Assert.Equal(0x00001000u, peHeader.SizeOfStackCommit);
Assert.Equal(0x00100000u, peHeader.SizeOfStackReserve);
Assert.Equal(0, peHeader.SizeOfUninitializedData);
Assert.Equal(Subsystem.WindowsCui, peHeader.Subsystem);
Assert.Equal(DllCharacteristics.DynamicBase | DllCharacteristics.NxCompatible | DllCharacteristics.NoSeh | DllCharacteristics.TerminalServerAware, peHeader.DllCharacteristics);
Assert.Equal(0u, peHeader.CheckSum);
Assert.Equal(0x2000, peHeader.FileAlignment);
Assert.Equal(0x10000000u, peHeader.ImageBase);
Assert.Equal(0x2000, peHeader.SectionAlignment);
Assert.Equal(0, peHeader.MajorImageVersion);
Assert.Equal(0, peHeader.MinorImageVersion);
Assert.Equal(0x30, peHeader.MajorLinkerVersion);
Assert.Equal(0, peHeader.MinorLinkerVersion);
Assert.Equal(4, peHeader.MajorOperatingSystemVersion);
Assert.Equal(0, peHeader.MinorOperatingSystemVersion);
Assert.Equal(4, peHeader.MajorSubsystemVersion);
Assert.Equal(0, peHeader.MinorSubsystemVersion);
Assert.Equal(16, peHeader.NumberOfRvaAndSizes);
Assert.Equal(0x2000, peHeader.SizeOfHeaders);
Assert.Equal(0x4000, peHeader.BaseRelocationTableDirectory.RelativeVirtualAddress);
Assert.Equal(0xc, peHeader.BaseRelocationTableDirectory.Size);
Assert.Equal(0, peHeader.BoundImportTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.BoundImportTableDirectory.Size);
Assert.Equal(0, peHeader.CertificateTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.CertificateTableDirectory.Size);
Assert.Equal(0, peHeader.CopyrightTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.CopyrightTableDirectory.Size);
Assert.Equal(0x2008, peHeader.CorHeaderTableDirectory.RelativeVirtualAddress);
Assert.Equal(0x48, peHeader.CorHeaderTableDirectory.Size);
Assert.Equal(0x2310, peHeader.DebugTableDirectory.RelativeVirtualAddress);
Assert.Equal(0x1C, peHeader.DebugTableDirectory.Size);
Assert.Equal(0, peHeader.ExceptionTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.ExceptionTableDirectory.Size);
Assert.Equal(0, peHeader.ExportTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.ExportTableDirectory.Size);
Assert.Equal(0x2000, peHeader.ImportAddressTableDirectory.RelativeVirtualAddress);
Assert.Equal(0x8, peHeader.ImportAddressTableDirectory.Size);
Assert.Equal(0x232C, peHeader.ImportTableDirectory.RelativeVirtualAddress);
Assert.Equal(0x4f, peHeader.ImportTableDirectory.Size);
Assert.Equal(0, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.LoadConfigTableDirectory.Size);
Assert.Equal(0, peHeader.ResourceTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.ResourceTableDirectory.Size);
Assert.Equal(0, peHeader.ThreadLocalStorageTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.ThreadLocalStorageTableDirectory.Size);
int importAddressTableDirectoryOffset;
Assert.True(peHeaders.TryGetDirectoryOffset(peHeader.ImportAddressTableDirectory, out importAddressTableDirectoryOffset));
Assert.Equal(0x2000, importAddressTableDirectoryOffset);
var importAddressTableDirectoryBytes = new byte[peHeader.ImportAddressTableDirectory.Size];
peStream.Position = importAddressTableDirectoryOffset;
peStream.Read(importAddressTableDirectoryBytes, 0, importAddressTableDirectoryBytes.Length);
AssertEx.Equal(new byte[]
{
0x60, 0x23, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}, importAddressTableDirectoryBytes);
int importTableDirectoryOffset;
Assert.True(peHeaders.TryGetDirectoryOffset(peHeader.ImportTableDirectory, out importTableDirectoryOffset));
Assert.Equal(0x232C, importTableDirectoryOffset);
var importTableDirectoryBytes = new byte[peHeader.ImportTableDirectory.Size];
peStream.Position = importTableDirectoryOffset;
peStream.Read(importTableDirectoryBytes, 0, importTableDirectoryBytes.Length);
AssertEx.Equal(new byte[]
{
0x54, 0x23, 0x00, 0x00, // RVA
0x00, 0x00, 0x00, 0x00, // 0
0x00, 0x00, 0x00, 0x00, // 0
0x6E, 0x23, 0x00, 0x00, // name RVA
0x00, 0x20, 0x00, 0x00, // ImportAddressTableDirectory RVA
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x60, 0x23, 0x00, 0x00, // hint RVA
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, // hint
(byte)'_', (byte)'C', (byte)'o', (byte)'r', (byte)'D', (byte)'l', (byte)'l', (byte)'M', (byte)'a', (byte)'i', (byte)'n', 0x00,
(byte)'m', (byte)'s', (byte)'c', (byte)'o', (byte)'r', (byte)'e', (byte)'e', (byte)'.', (byte)'d', (byte)'l', (byte)'l', 0x00,
0x00
}, importTableDirectoryBytes);
var entryPointSectionIndex = peHeaders.GetContainingSectionIndex(peHeader.AddressOfEntryPoint);
Assert.Equal(0, entryPointSectionIndex);
peStream.Position = peHeaders.SectionHeaders[0].PointerToRawData + peHeader.AddressOfEntryPoint - peHeaders.SectionHeaders[0].VirtualAddress;
byte[] startupStub = new byte[8];
peStream.Read(startupStub, 0, startupStub.Length);
AssertEx.Equal(new byte[] { 0xFF, 0x25, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00 }, startupStub);
Assert.Equal(Characteristics.Dll | Characteristics.LargeAddressAware | Characteristics.ExecutableImage, coffHeader.Characteristics);
Assert.Equal(Machine.I386, coffHeader.Machine);
Assert.Equal(2, coffHeader.NumberOfSections);
Assert.Equal(0, coffHeader.NumberOfSymbols);
Assert.Equal(0, coffHeader.PointerToSymbolTable);
Assert.Equal(0xe0, coffHeader.SizeOfOptionalHeader);
Assert.Equal(-609278808, coffHeader.TimeDateStamp);
Assert.Equal(0, corHeader.EntryPointTokenOrRelativeVirtualAddress);
Assert.Equal(CorFlags.ILOnly, corHeader.Flags);
Assert.Equal(2, corHeader.MajorRuntimeVersion);
Assert.Equal(5, corHeader.MinorRuntimeVersion);
Assert.Equal(0, corHeader.CodeManagerTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.CodeManagerTableDirectory.Size);
Assert.Equal(0, corHeader.ExportAddressTableJumpsDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.ExportAddressTableJumpsDirectory.Size);
Assert.Equal(0, corHeader.ManagedNativeHeaderDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.ManagedNativeHeaderDirectory.Size);
Assert.Equal(0x2058, corHeader.MetadataDirectory.RelativeVirtualAddress);
Assert.Equal(0x02b8, corHeader.MetadataDirectory.Size);
Assert.Equal(0, corHeader.ResourcesDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.ResourcesDirectory.Size);
Assert.Equal(0, corHeader.StrongNameSignatureDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.StrongNameSignatureDirectory.Size);
Assert.Equal(0, corHeader.VtableFixupsDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.VtableFixupsDirectory.Size);
var sections = peHeaders.SectionHeaders;
Assert.Equal(2, sections.Length);
Assert.Equal(".text", sections[0].Name);
Assert.Equal(0, sections[0].NumberOfLineNumbers);
Assert.Equal(0, sections[0].NumberOfRelocations);
Assert.Equal(0, sections[0].PointerToLineNumbers);
Assert.Equal(0x2000, sections[0].PointerToRawData);
Assert.Equal(0, sections[0].PointerToRelocations);
Assert.Equal(SectionCharacteristics.ContainsCode | SectionCharacteristics.MemExecute | SectionCharacteristics.MemRead, sections[0].SectionCharacteristics);
Assert.Equal(0x2000, sections[0].SizeOfRawData);
Assert.Equal(0x2000, sections[0].VirtualAddress);
Assert.Equal(900, sections[0].VirtualSize);
Assert.Equal(".reloc", sections[1].Name);
Assert.Equal(0, sections[1].NumberOfLineNumbers);
Assert.Equal(0, sections[1].NumberOfRelocations);
Assert.Equal(0, sections[1].PointerToLineNumbers);
Assert.Equal(0x4000, sections[1].PointerToRawData);
Assert.Equal(0, sections[1].PointerToRelocations);
Assert.Equal(SectionCharacteristics.ContainsInitializedData | SectionCharacteristics.MemDiscardable | SectionCharacteristics.MemRead, sections[1].SectionCharacteristics);
Assert.Equal(0x2000, sections[1].SizeOfRawData);
Assert.Equal(0x4000, sections[1].VirtualAddress);
Assert.Equal(12, sections[1].VirtualSize);
var relocBlock = peReader.GetSectionData(sections[1].VirtualAddress);
var relocBytes = new byte[sections[1].VirtualSize];
Marshal.Copy((IntPtr)relocBlock.Pointer, relocBytes, 0, relocBytes.Length);
AssertEx.Equal(new byte[] { 0, 0x20, 0, 0, 0x0c, 0, 0, 0, 0x80, 0x33, 0, 0 }, relocBytes);
}
[Fact]
public void PEHeaders2()
{
var options = EmitOptions.Default.
WithFileAlignment(512).
WithBaseAddress(0x123456789ABCDEF).
WithHighEntropyVirtualAddressSpace(true).
WithSubsystemVersion(SubsystemVersion.WindowsXP);
var syntax = SyntaxFactory.ParseSyntaxTree(@"class C { static void Main() { } }", TestOptions.Regular.WithNoRefSafetyRulesAttribute());
var peStream = CreateCompilationWithMscorlib40(
syntax,
options: TestOptions.DebugExe.WithPlatform(Platform.X64).WithDeterministic(true),
assemblyName: "B37A4FCD-ED76-4924-A2AD-298836056E00").EmitToStream(options);
peStream.Position = 0;
var peHeaders = new PEHeaders(peStream);
var peHeader = peHeaders.PEHeader;
var coffHeader = peHeaders.CoffHeader;
var corHeader = peHeaders.CorHeader;
Assert.Equal(PEMagic.PE32Plus, peHeader.Magic);
Assert.Equal(0x00000000, peHeader.AddressOfEntryPoint);
Assert.Equal(0x00002000, peHeader.BaseOfCode);
Assert.Equal(0x00000000, peHeader.BaseOfData);
Assert.Equal(0x00000200, peHeader.SizeOfHeaders);
Assert.Equal(0x00000400, peHeader.SizeOfCode);
Assert.Equal(0x00002000u, peHeader.SizeOfHeapCommit);
Assert.Equal(0x00100000u, peHeader.SizeOfHeapReserve);
Assert.Equal(0x00004000, peHeader.SizeOfImage);
Assert.Equal(0x00000000, peHeader.SizeOfInitializedData);
Assert.Equal(0x00004000u, peHeader.SizeOfStackCommit);
Assert.Equal(0x0400000u, peHeader.SizeOfStackReserve);
Assert.Equal(0, peHeader.SizeOfUninitializedData);
Assert.Equal(Subsystem.WindowsCui, peHeader.Subsystem);
Assert.Equal(0u, peHeader.CheckSum);
Assert.Equal(0x200, peHeader.FileAlignment);
Assert.Equal(0x0123456789ac0000u, peHeader.ImageBase);
Assert.Equal(0x2000, peHeader.SectionAlignment);
Assert.Equal(0, peHeader.MajorImageVersion);
Assert.Equal(0, peHeader.MinorImageVersion);
Assert.Equal(0x30, peHeader.MajorLinkerVersion);
Assert.Equal(0, peHeader.MinorLinkerVersion);
Assert.Equal(4, peHeader.MajorOperatingSystemVersion);
Assert.Equal(0, peHeader.MinorOperatingSystemVersion);
Assert.Equal(5, peHeader.MajorSubsystemVersion);
Assert.Equal(1, peHeader.MinorSubsystemVersion);
Assert.Equal(16, peHeader.NumberOfRvaAndSizes);
Assert.Equal(0x200, peHeader.SizeOfHeaders);
Assert.Equal(0, peHeader.BaseRelocationTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.BaseRelocationTableDirectory.Size);
Assert.Equal(0, peHeader.BoundImportTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.BoundImportTableDirectory.Size);
Assert.Equal(0, peHeader.CertificateTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.CertificateTableDirectory.Size);
Assert.Equal(0, peHeader.CopyrightTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.CopyrightTableDirectory.Size);
Assert.Equal(0x2000, peHeader.CorHeaderTableDirectory.RelativeVirtualAddress);
Assert.Equal(0x48, peHeader.CorHeaderTableDirectory.Size);
Assert.Equal(0x2324, peHeader.DebugTableDirectory.RelativeVirtualAddress);
Assert.Equal(0x1C, peHeader.DebugTableDirectory.Size);
Assert.Equal(0, peHeader.ExceptionTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.ExceptionTableDirectory.Size);
Assert.Equal(0, peHeader.ExportTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.ExportTableDirectory.Size);
Assert.Equal(0, peHeader.ImportAddressTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.ImportAddressTableDirectory.Size);
Assert.Equal(0, peHeader.ImportTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.ImportTableDirectory.Size);
Assert.Equal(0, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.LoadConfigTableDirectory.Size);
Assert.Equal(0, peHeader.ResourceTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.ResourceTableDirectory.Size);
Assert.Equal(0, peHeader.ThreadLocalStorageTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, peHeader.ThreadLocalStorageTableDirectory.Size);
Assert.Equal(Characteristics.LargeAddressAware | Characteristics.ExecutableImage, coffHeader.Characteristics);
Assert.Equal(Machine.Amd64, coffHeader.Machine);
Assert.Equal(1, coffHeader.NumberOfSections);
Assert.Equal(0, coffHeader.NumberOfSymbols);
Assert.Equal(0, coffHeader.PointerToSymbolTable);
Assert.Equal(240, coffHeader.SizeOfOptionalHeader);
Assert.Equal(-1823671907, coffHeader.TimeDateStamp);
Assert.Equal(0x06000001, corHeader.EntryPointTokenOrRelativeVirtualAddress);
Assert.Equal(CorFlags.ILOnly, corHeader.Flags);
Assert.Equal(2, corHeader.MajorRuntimeVersion);
Assert.Equal(5, corHeader.MinorRuntimeVersion);
Assert.Equal(0, corHeader.CodeManagerTableDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.CodeManagerTableDirectory.Size);
Assert.Equal(0, corHeader.ExportAddressTableJumpsDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.ExportAddressTableJumpsDirectory.Size);
Assert.Equal(0, corHeader.ManagedNativeHeaderDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.ManagedNativeHeaderDirectory.Size);
Assert.Equal(0x2054, corHeader.MetadataDirectory.RelativeVirtualAddress);
Assert.Equal(0x02d0, corHeader.MetadataDirectory.Size);
Assert.Equal(0, corHeader.ResourcesDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.ResourcesDirectory.Size);
Assert.Equal(0, corHeader.StrongNameSignatureDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.StrongNameSignatureDirectory.Size);
Assert.Equal(0, corHeader.VtableFixupsDirectory.RelativeVirtualAddress);
Assert.Equal(0, corHeader.VtableFixupsDirectory.Size);
var sections = peHeaders.SectionHeaders;
Assert.Equal(1, sections.Length);
Assert.Equal(".text", sections[0].Name);
Assert.Equal(0, sections[0].NumberOfLineNumbers);
Assert.Equal(0, sections[0].NumberOfRelocations);
Assert.Equal(0, sections[0].PointerToLineNumbers);
Assert.Equal(0x200, sections[0].PointerToRawData);
Assert.Equal(0, sections[0].PointerToRelocations);
Assert.Equal(SectionCharacteristics.ContainsCode | SectionCharacteristics.MemExecute | SectionCharacteristics.MemRead, sections[0].SectionCharacteristics);
Assert.Equal(0x400, sections[0].SizeOfRawData);
Assert.Equal(0x2000, sections[0].VirtualAddress);
Assert.Equal(832, sections[0].VirtualSize);
}
[Fact]
public void InParametersShouldHaveMetadataIn_TypeMethods()
{
var text = @"
using System.Runtime.InteropServices;
class T
{
public void M(in int a, [In]in int b, [In]int c, int d) {}
}";
Action<ModuleSymbol> verifier = module =>
{
var parameters = module.GlobalNamespace.GetTypeMember("T").GetMethod("M").GetParameters();
Assert.Equal(4, parameters.Length);
Assert.True(parameters[0].IsMetadataIn);
Assert.True(parameters[1].IsMetadataIn);
Assert.True(parameters[2].IsMetadataIn);
Assert.False(parameters[3].IsMetadataIn);
};
CompileAndVerify(text, sourceSymbolValidator: verifier, symbolValidator: verifier);
}
[Fact]
public void InParametersShouldHaveMetadataIn_IndexerMethods()
{
var text = @"
using System.Runtime.InteropServices;
class T
{
public int this[in int a, [In]in int b, [In]int c, int d] => 0;
}";
Action<ModuleSymbol> verifier = module =>
{
var parameters = module.GlobalNamespace.GetTypeMember("T").GetMethod("get_Item").GetParameters();
Assert.Equal(4, parameters.Length);
Assert.True(parameters[0].IsMetadataIn);
Assert.True(parameters[1].IsMetadataIn);
Assert.True(parameters[2].IsMetadataIn);
Assert.False(parameters[3].IsMetadataIn);
};
CompileAndVerify(text, sourceSymbolValidator: verifier, symbolValidator: verifier);
}
[Fact]
public void InParametersShouldHaveMetadataIn_Delegates()
{
var text = @"
using System.Runtime.InteropServices;
public delegate void D(in int a, [In]in int b, [In]int c, int d);
public class C
{
public void M()
{
N((in int a, in int b, int c, int d) => {});
}
public void N(D lambda) { }
}
";
CompileAndVerify(text,
options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All),
sourceSymbolValidator: module =>
{
var parameters = module.ContainingAssembly.GetTypeByMetadataName("D").DelegateInvokeMethod.Parameters;
Assert.Equal(4, parameters.Length);
Assert.True(parameters[0].IsMetadataIn);
Assert.True(parameters[1].IsMetadataIn);
Assert.True(parameters[2].IsMetadataIn);
Assert.False(parameters[3].IsMetadataIn);
},
symbolValidator: module =>
{
var delegateParameters = module.ContainingAssembly.GetTypeByMetadataName("D").DelegateInvokeMethod.Parameters;
Assert.Equal(4, delegateParameters.Length);
Assert.True(delegateParameters[0].IsMetadataIn);
Assert.True(delegateParameters[1].IsMetadataIn);
Assert.True(delegateParameters[2].IsMetadataIn);
Assert.False(delegateParameters[3].IsMetadataIn);
var lambdaParameters = module.GlobalNamespace.GetTypeMember("C").GetTypeMember("<>c").GetMethod("<M>b__0_0").Parameters;
Assert.Equal(4, lambdaParameters.Length);
Assert.True(lambdaParameters[0].IsMetadataIn);
Assert.True(lambdaParameters[1].IsMetadataIn);
Assert.False(lambdaParameters[2].IsMetadataIn);
Assert.False(lambdaParameters[3].IsMetadataIn);
});
}
[Fact]
public void InParametersShouldHaveMetadataIn_LocalFunctions()
{
var text = @"
using System.Runtime.InteropServices;
public class C
{
public void M()
{
void local(in int a, int c) { }
}
}
";
CompileAndVerify(text, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: module =>
{
var parameters = module.GlobalNamespace.GetTypeMember("C").GetMember("<M>g__local|0_0").GetParameters();
Assert.Equal(2, parameters.Length);
Assert.True(parameters[0].IsMetadataIn);
Assert.False(parameters[1].IsMetadataIn);
});
}
[Fact]
public void InParametersShouldHaveMetadataIn_ExternMethods()
{
var text = @"
using System.Runtime.InteropServices;
class T
{
[DllImport(""Other.dll"")]
public static extern void M(in int a, [In]in int b, [In]int c, int d);
}";
Action<ModuleSymbol> verifier = module =>
{
var parameters = module.GlobalNamespace.GetTypeMember("T").GetMethod("M").GetParameters();
Assert.Equal(4, parameters.Length);
Assert.True(parameters[0].IsMetadataIn);
Assert.True(parameters[1].IsMetadataIn);
Assert.True(parameters[2].IsMetadataIn);
Assert.False(parameters[3].IsMetadataIn);
};
CompileAndVerify(text, sourceSymbolValidator: verifier, symbolValidator: verifier);
}
[Fact]
public void InParametersShouldHaveMetadataIn_NoPIA()
{
var comAssembly = CreateCompilationWithMscorlib40(@"
using System;
using System.Runtime.InteropServices;
[assembly: ImportedFromTypeLib(""test.dll"")]
[assembly: Guid(""6681dcd6-9c3e-4c3a-b04a-aef3ee85c2cf"")]
[ComImport()]
[Guid(""6681dcd6-9c3e-4c3a-b04a-aef3ee85c2cf"")]
public interface T
{
void M(in int a, [In]in int b, [In]int c, int d);
}");
CompileAndVerify(comAssembly, symbolValidator: module =>
{
var parameters = module.GlobalNamespace.GetTypeMember("T").GetMethod("M").GetParameters();
Assert.Equal(4, parameters.Length);
Assert.True(parameters[0].IsMetadataIn);
Assert.True(parameters[1].IsMetadataIn);
Assert.True(parameters[2].IsMetadataIn);
Assert.False(parameters[3].IsMetadataIn);
});
var code = @"
class User
{
public void M(T obj)
{
obj.M(1, 2, 3, 4);
}
}";
CompileAndVerify(
source: code,
options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All),
references: new[] { comAssembly.EmitToImageReference(embedInteropTypes: true) },
symbolValidator: module =>
{
var parameters = module.GlobalNamespace.GetTypeMember("T").GetMethod("M").GetParameters();
Assert.Equal(4, parameters.Length);
Assert.True(parameters[0].IsMetadataIn);
Assert.True(parameters[1].IsMetadataIn);
Assert.True(parameters[2].IsMetadataIn);
Assert.False(parameters[3].IsMetadataIn);
});
}
[Fact]
public void ExtendingInParametersFromParentWithoutInAttributeWorksWithoutErrors()
{
var reference = CompileIL(@"
.class private auto ansi sealed beforefieldinit Microsoft.CodeAnalysis.EmbeddedAttribute extends [mscorlib]System.Attribute
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (01 00 00 00)
.custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = (01 00 00 00)
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Attribute::.ctor()
IL_0006: nop
IL_0007: ret
}
}
.class private auto ansi sealed beforefieldinit System.Runtime.CompilerServices.IsReadOnlyAttribute extends [mscorlib]System.Attribute
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (01 00 00 00)
.custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = (01 00 00 00)
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Attribute::.ctor()
IL_0006: nop
IL_0007: ret
}
}
.class public auto ansi beforefieldinit Parent extends [mscorlib]System.Object
{
.method public hidebysig newslot virtual instance void M (
int32& modreq([mscorlib]System.Runtime.InteropServices.InAttribute) a,
int32& modreq([mscorlib]System.Runtime.InteropServices.InAttribute) b,
int32 c,
int32 d) cil managed
{
.param [1] .custom instance void System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (01 00 00 00)
.param [2] .custom instance void System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (01 00 00 00)
.maxstack 8
IL_0000: nop
IL_0001: ldstr ""Parent called""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
}
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib] System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}");
var comp = CreateCompilation(@"
using System;
using System.Runtime.InteropServices;
public class Child : Parent
{
public override void M(in int a, [In]in int b, [In]int c, int d)
{
base.M(a, b, c, d);
Console.WriteLine(""Child called"");
}
}
public static class Program
{
public static void Main()
{
var obj = new Child();
obj.M(1, 2, 3, 4);
}
}", new[] { reference }, TestOptions.ReleaseExe);
var parentParameters = comp.GetTypeByMetadataName("Parent").GetMethod("M").GetParameters();
Assert.Equal(4, parentParameters.Length);
Assert.False(parentParameters[0].IsMetadataIn);
Assert.False(parentParameters[1].IsMetadataIn);
Assert.False(parentParameters[2].IsMetadataIn);
Assert.False(parentParameters[3].IsMetadataIn);
var expectedOutput =
@"Parent called
Child called";
CompileAndVerify(comp, expectedOutput: expectedOutput, symbolValidator: module =>
{
var childParameters = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").GetParameters();
Assert.Equal(4, childParameters.Length);
Assert.True(childParameters[0].IsMetadataIn);
Assert.True(childParameters[1].IsMetadataIn);
Assert.True(childParameters[2].IsMetadataIn);
Assert.False(childParameters[3].IsMetadataIn);
});
}
[Fact]
public void GeneratingProxyForVirtualMethodInParentCopiesMetadataBitsCorrectly_OutAttribute()
{
var reference = CreateCompilation(@"
using System.Runtime.InteropServices;
public class Parent
{
public void M(out int a, [Out] int b) => throw null;
}");
CompileAndVerify(reference, symbolValidator: module =>
{
var sourceParentParameters = module.GlobalNamespace.GetTypeMember("Parent").GetMethod("M").GetParameters();
Assert.Equal(2, sourceParentParameters.Length);
Assert.True(sourceParentParameters[0].IsMetadataOut);
Assert.True(sourceParentParameters[1].IsMetadataOut);
});
var source = @"
using System.Runtime.InteropServices;
public interface IParent
{
void M(out int a, [Out] int b);
}
public class Child : Parent, IParent
{
}";
CompileAndVerify(
source: source,
references: new[] { reference.EmitToImageReference() },
options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All),
symbolValidator: module =>
{
var interfaceParameters = module.GlobalNamespace.GetTypeMember("IParent").GetMethod("M").GetParameters();
Assert.Equal(2, interfaceParameters.Length);
Assert.True(interfaceParameters[0].IsMetadataOut);
Assert.True(interfaceParameters[1].IsMetadataOut);
var proxyChildParameters = module.GlobalNamespace.GetTypeMember("Child").GetMethod("IParent.M").GetParameters();
Assert.Equal(2, proxyChildParameters.Length);
Assert.True(proxyChildParameters[0].IsMetadataOut);
Assert.False(proxyChildParameters[1].IsMetadataOut); // User placed attributes are not copied.
});
}
[Fact]
public void GeneratingProxyForVirtualMethodInParentCopiesMetadataBitsCorrectly_InAttribute()
{
var reference = CreateCompilation(@"
using System.Runtime.InteropServices;
public class Parent
{
public void M(in int a, [In] int b) => throw null;
}");
CompileAndVerify(reference, symbolValidator: module =>
{
var sourceParentParameters = module.GlobalNamespace.GetTypeMember("Parent").GetMethod("M").GetParameters();
Assert.Equal(2, sourceParentParameters.Length);
Assert.True(sourceParentParameters[0].IsMetadataIn);
Assert.True(sourceParentParameters[1].IsMetadataIn);
});
var source = @"
using System.Runtime.InteropServices;
public interface IParent
{
void M(in int a, [In] int b);
}
public class Child : Parent, IParent
{
}";
CompileAndVerify(
source: source,
references: new[] { reference.EmitToImageReference() },
options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All),
symbolValidator: module =>
{
var interfaceParameters = module.GlobalNamespace.GetTypeMember("IParent").GetMethod("M").GetParameters();
Assert.Equal(2, interfaceParameters.Length);
Assert.True(interfaceParameters[0].IsMetadataIn);
Assert.True(interfaceParameters[1].IsMetadataIn);
var proxyChildParameters = module.GlobalNamespace.GetTypeMember("Child").GetMethod("IParent.M").GetParameters();
Assert.Equal(2, proxyChildParameters.Length);
Assert.True(proxyChildParameters[0].IsMetadataIn);
Assert.False(proxyChildParameters[1].IsMetadataIn); // User placed attributes are not copied.
});
}
}
}
|