diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index 8d0d4d333..da41f0e6d 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -69,6 +69,8 @@ + + diff --git a/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs new file mode 100644 index 000000000..59ec45de0 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs @@ -0,0 +1,1784 @@ +// Copyright (c) 2010-2018 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using ICSharpCode.Decompiler.Semantics; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.TypeSystem.Implementation; +using NUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests.TypeSystem +{ + public class TypeSystemLoaderTests + { + static readonly Lazy mscorlib = new Lazy( + delegate { + return new CecilLoader().LoadAssemblyFile(typeof(object).Assembly.Location); + }); + + static readonly Lazy systemCore = new Lazy( + delegate { + return new CecilLoader().LoadAssemblyFile(typeof(System.Linq.Enumerable).Assembly.Location); + }); + + public static IUnresolvedAssembly Mscorlib { get { return mscorlib.Value; } } + public static IUnresolvedAssembly SystemCore { get { return systemCore.Value; } } + + [OneTimeSetUp] + public void FixtureSetUp() + { + // use "IncludeInternalMembers" so that Cecil results match C# parser results + CecilLoader loader = new CecilLoader() { IncludeInternalMembers = true }; + IUnresolvedAssembly asm = loader.LoadAssemblyFile(typeof(SimplePublicClass).Assembly.Location); + compilation = new SimpleCompilation(asm, Mscorlib); + } + + protected ICompilation compilation; + + protected ITypeDefinition GetTypeDefinition(Type type) + { + return compilation.FindType(type).GetDefinition(); + } + + [Test] + public void SimplePublicClassTest() + { + ITypeDefinition c = GetTypeDefinition(typeof(SimplePublicClass)); + Assert.AreEqual(typeof(SimplePublicClass).Name, c.Name); + Assert.AreEqual(typeof(SimplePublicClass).FullName, c.FullName); + Assert.AreEqual(typeof(SimplePublicClass).Namespace, c.Namespace); + Assert.AreEqual(typeof(SimplePublicClass).FullName, c.ReflectionName); + + Assert.AreEqual(Accessibility.Public, c.Accessibility); + Assert.IsFalse(c.IsAbstract); + Assert.IsFalse(c.IsSealed); + Assert.IsFalse(c.IsStatic); + Assert.IsFalse(c.IsShadowing); + } + + [Test] + public void SimplePublicClassMethodTest() + { + ITypeDefinition c = GetTypeDefinition(typeof(SimplePublicClass)); + + IMethod method = c.Methods.Single(m => m.Name == "Method"); + Assert.AreEqual(typeof(SimplePublicClass).FullName + ".Method", method.FullName); + Assert.AreSame(c, method.DeclaringType); + Assert.AreEqual(Accessibility.Public, method.Accessibility); + Assert.AreEqual(SymbolKind.Method, method.SymbolKind); + Assert.IsFalse(method.IsVirtual); + Assert.IsFalse(method.IsStatic); + Assert.AreEqual(0, method.Parameters.Count); + Assert.AreEqual(0, method.Attributes.Count); + Assert.IsTrue(method.HasBody); + Assert.IsNull(method.AccessorOwner); + } + + [Test] + public void DynamicType() + { + ITypeDefinition testClass = GetTypeDefinition(typeof(DynamicTest)); + Assert.AreEqual(SpecialType.Dynamic, testClass.Properties.Single().ReturnType); + Assert.AreEqual(0, testClass.Properties.Single().Attributes.Count); + } +#if !__MonoCS__ + + [Test] + public void DynamicTypeInGenerics() + { + ITypeDefinition testClass = GetTypeDefinition(typeof(DynamicTest)); + + IMethod m1 = testClass.Methods.Single(me => me.Name == "DynamicGenerics1"); + Assert.AreEqual("System.Collections.Generic.List`1[[dynamic]]", m1.ReturnType.ReflectionName); + Assert.AreEqual("System.Action`3[[System.Object],[dynamic[]],[System.Object]]", m1.Parameters[0].Type.ReflectionName); + + IMethod m2 = testClass.Methods.Single(me => me.Name == "DynamicGenerics2"); + Assert.AreEqual("System.Action`3[[System.Object],[dynamic],[System.Object]]", m2.Parameters[0].Type.ReflectionName); + + IMethod m3 = testClass.Methods.Single(me => me.Name == "DynamicGenerics3"); + Assert.AreEqual("System.Action`3[[System.Int32],[dynamic],[System.Object]]", m3.Parameters[0].Type.ReflectionName); + + IMethod m4 = testClass.Methods.Single(me => me.Name == "DynamicGenerics4"); + Assert.AreEqual("System.Action`3[[System.Int32[]],[dynamic],[System.Object]]", m4.Parameters[0].Type.ReflectionName); + + IMethod m5 = testClass.Methods.Single(me => me.Name == "DynamicGenerics5"); + Assert.AreEqual("System.Action`3[[System.Int32*[]],[dynamic],[System.Object]]", m5.Parameters[0].Type.ReflectionName); + + IMethod m6 = testClass.Methods.Single(me => me.Name == "DynamicGenerics6"); + Assert.AreEqual("System.Action`3[[System.Object],[dynamic],[System.Object]]&", m6.Parameters[0].Type.ReflectionName); + + IMethod m7 = testClass.Methods.Single(me => me.Name == "DynamicGenerics7"); + Assert.AreEqual("System.Action`3[[System.Int32[][,]],[dynamic],[System.Object]]", m7.Parameters[0].Type.ReflectionName); + } +#endif + + [Test] + public void DynamicParameterHasNoAttributes() + { + ITypeDefinition testClass = GetTypeDefinition(typeof(DynamicTest)); + IMethod m1 = testClass.Methods.Single(me => me.Name == "DynamicGenerics1"); + Assert.AreEqual(0, m1.Parameters[0].Attributes.Count); + } + + [Test] + public void AssemblyAttribute() + { + var attributes = compilation.MainAssembly.AssemblyAttributes; + var typeTest = attributes.Single(a => a.AttributeType.FullName == typeof(TypeTestAttribute).FullName); + Assert.AreEqual(3, typeTest.PositionalArguments.Count); + // first argument is (int)42 + Assert.AreEqual(42, (int)typeTest.PositionalArguments[0].ConstantValue); + // second argument is typeof(System.Action<>) + TypeOfResolveResult rt = (TypeOfResolveResult)typeTest.PositionalArguments[1]; + Assert.IsFalse(rt.ReferencedType is ParameterizedType); // rt must not be constructed - it's just an unbound type + Assert.AreEqual("System.Action", rt.ReferencedType.FullName); + Assert.AreEqual(1, rt.ReferencedType.TypeParameterCount); + // third argument is typeof(IDictionary>) + rt = (TypeOfResolveResult)typeTest.PositionalArguments[2]; + ParameterizedType crt = (ParameterizedType)rt.ReferencedType; + Assert.AreEqual("System.Collections.Generic.IDictionary", crt.FullName); + Assert.AreEqual("System.String", crt.TypeArguments[0].FullName); + // we know the name for TestAttribute, but not necessarily the namespace, as NUnit is not in the compilation + Assert.AreEqual("System.Collections.Generic.IList", crt.TypeArguments[1].FullName); + var testAttributeType = ((ParameterizedType)crt.TypeArguments[1]).TypeArguments.Single(); + Assert.AreEqual("TestAttribute", testAttributeType.Name); + Assert.AreEqual(TypeKind.Unknown, testAttributeType.Kind); + // (more accurately, we know the namespace and reflection name if the type was loaded by cecil, + // but not if we parsed it from C#) + } + + [Test] + public void TypeForwardedTo_Attribute() + { + var attributes = compilation.MainAssembly.AssemblyAttributes; + var forwardAttribute = attributes.Single(a => a.AttributeType.FullName == typeof(TypeForwardedToAttribute).FullName); + Assert.AreEqual(1, forwardAttribute.PositionalArguments.Count); + TypeOfResolveResult rt = (TypeOfResolveResult)forwardAttribute.PositionalArguments[0]; + Assert.AreEqual("System.Func`2", rt.ReferencedType.ReflectionName); + } + + [Test] + public void TestClassTypeParameters() + { + var testClass = GetTypeDefinition(typeof(GenericClass<,>)); + Assert.AreEqual(SymbolKind.TypeDefinition, testClass.TypeParameters[0].OwnerType); + Assert.AreEqual(SymbolKind.TypeDefinition, testClass.TypeParameters[1].OwnerType); + Assert.AreSame(testClass.TypeParameters[1], testClass.TypeParameters[0].DirectBaseTypes.First()); + } + + [Test] + public void TestMethod() + { + var testClass = GetTypeDefinition(typeof(GenericClass<,>)); + + IMethod m = testClass.Methods.Single(me => me.Name == "TestMethod"); + Assert.AreEqual("K", m.TypeParameters[0].Name); + Assert.AreEqual("V", m.TypeParameters[1].Name); + Assert.AreEqual(SymbolKind.Method, m.TypeParameters[0].OwnerType); + Assert.AreEqual(SymbolKind.Method, m.TypeParameters[1].OwnerType); + + Assert.AreEqual("System.IComparable`1[[``1]]", m.TypeParameters[0].DirectBaseTypes.First().ReflectionName); + Assert.AreSame(m.TypeParameters[0], m.TypeParameters[1].DirectBaseTypes.First()); + } + + [Test] + public void GetIndex() + { + var testClass = GetTypeDefinition(typeof(GenericClass<,>)); + + IMethod m = testClass.Methods.Single(me => me.Name == "GetIndex"); + Assert.AreEqual("T", m.TypeParameters[0].Name); + Assert.AreEqual(SymbolKind.Method, m.TypeParameters[0].OwnerType); + Assert.AreSame(m, m.TypeParameters[0].Owner); + + ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].DirectBaseTypes.First(); + Assert.AreEqual("IEquatable", constraint.Name); + Assert.AreEqual(1, constraint.TypeParameterCount); + Assert.AreEqual(1, constraint.TypeArguments.Count); + Assert.AreSame(m.TypeParameters[0], constraint.TypeArguments[0]); + Assert.AreSame(m.TypeParameters[0], m.Parameters[0].Type); + } + + [Test] + public void GetIndexSpecializedTypeParameter() + { + var testClass = GetTypeDefinition(typeof(GenericClass<,>)); + var methodDef = testClass.Methods.Single(me => me.Name == "GetIndex"); + var m = methodDef.Specialize(new TypeParameterSubstitution( + new[] { compilation.FindType(KnownTypeCode.Int16), compilation.FindType(KnownTypeCode.Int32) }, + null + )); + + Assert.AreEqual("T", m.TypeParameters[0].Name); + Assert.AreEqual(SymbolKind.Method, m.TypeParameters[0].OwnerType); + Assert.AreSame(m, m.TypeParameters[0].Owner); + + ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].DirectBaseTypes.First(); + Assert.AreEqual("IEquatable", constraint.Name); + Assert.AreEqual(1, constraint.TypeParameterCount); + Assert.AreEqual(1, constraint.TypeArguments.Count); + Assert.AreSame(m.TypeParameters[0], constraint.TypeArguments[0]); + Assert.AreSame(m.TypeParameters[0], m.Parameters[0].Type); + } + + [Test] + public void GetIndexDoubleSpecialization() + { + var testClass = GetTypeDefinition(typeof(GenericClass<,>)); + // GenericClass.GetIndex + var methodDef = testClass.Methods.Single(me => me.Name == "GetIndex"); + + // GenericClass.GetIndex + var m1 = methodDef.Specialize(new TypeParameterSubstitution( + new[] { testClass.TypeParameters[1], testClass.TypeParameters[0] }, + new[] { testClass.TypeParameters[0] } + )); + // GenericClass.GetIndex + var m2 = m1.Specialize(new TypeParameterSubstitution( + new[] { compilation.FindType(KnownTypeCode.Int32), compilation.FindType(KnownTypeCode.String) }, + null + )); + + // GenericClass.GetIndex + var m12 = methodDef.Specialize(new TypeParameterSubstitution( + new[] { compilation.FindType(KnownTypeCode.String), compilation.FindType(KnownTypeCode.Int32) }, + new[] { compilation.FindType(KnownTypeCode.Int32) } + )); + Assert.AreEqual(m12, m2); + } + + [Test] + public void SpecializedMethod_AccessorOwner() + { + // NRefactory bug #143 - Accessor Owner throws null reference exception in some cases now + var method = compilation.FindType(typeof(GenericClass)).GetMethods(m => m.Name == "GetIndex").Single(); + Assert.IsNull(method.AccessorOwner); + } + + [Test] + public void Specialized_GetIndex_ToMemberReference() + { + var method = compilation.FindType(typeof(GenericClass)).GetMethods(m => m.Name == "GetIndex").Single(); + Assert.AreSame(method.TypeParameters[0], method.Parameters[0].Type); + Assert.AreSame(method, method.TypeParameters[0].Owner); + Assert.IsInstanceOf(method); + //Assert.IsFalse(method.IsParameterized); // the method itself is not specialized + Assert.AreEqual(method.TypeParameters, method.TypeArguments); + } + + [Test] + public void Specialized_GetIndex_SpecializeWithIdentityHasNoEffect() + { + var genericClass = compilation.FindType(typeof(GenericClass)); + IType[] methodTypeArguments = { DummyTypeParameter.GetMethodTypeParameter(0) }; + var method = genericClass.GetMethods(methodTypeArguments, m => m.Name == "GetIndex").Single(); + // GenericClass.GetIndex() + Assert.AreSame(method, method.TypeParameters[0].Owner); + Assert.AreNotEqual(method.TypeParameters[0], method.TypeArguments[0]); + Assert.IsNull(((ITypeParameter)method.TypeArguments[0]).Owner); + // Now apply identity substitution: + var method2 = method.Specialize(TypeParameterSubstitution.Identity); + Assert.AreSame(method2, method2.TypeParameters[0].Owner); + Assert.AreNotEqual(method2.TypeParameters[0], method2.TypeArguments[0]); + Assert.IsNull(((ITypeParameter)method2.TypeArguments[0]).Owner); + + Assert.AreEqual(method, method2); + } + + [Test] + public void GenericEnum() + { + var testClass = GetTypeDefinition(typeof(GenericClass<,>.NestedEnum)); + Assert.AreEqual(2, testClass.TypeParameterCount); + } + + [Test] + public void FieldInGenericClassWithNestedEnumType() + { + var testClass = GetTypeDefinition(typeof(GenericClass<,>)); + var enumClass = GetTypeDefinition(typeof(GenericClass<,>.NestedEnum)); + var field = testClass.Fields.Single(f => f.Name == "EnumField"); + Assert.AreEqual(new ParameterizedType(enumClass, testClass.TypeParameters), field.ReturnType); + } + + [Test] + public void GenericEnumMemberReturnType() + { + var enumClass = GetTypeDefinition(typeof(GenericClass<,>.NestedEnum)); + var field = enumClass.Fields.Single(f => f.Name == "EnumMember"); + Assert.AreEqual(new ParameterizedType(enumClass, enumClass.TypeParameters), field.ReturnType); + } + + [Test] + public void PropertyWithProtectedSetter() + { + var testClass = GetTypeDefinition(typeof(PropertyTest)); + IProperty p = testClass.Properties.Single(pr => pr.Name == "PropertyWithProtectedSetter"); + Assert.IsTrue(p.CanGet); + Assert.IsTrue(p.CanSet); + Assert.AreEqual(Accessibility.Public, p.Accessibility); + Assert.AreEqual(Accessibility.Public, p.Getter.Accessibility); + Assert.AreEqual(Accessibility.Protected, p.Setter.Accessibility); + } + + [Test] + public void PropertyWithPrivateSetter() + { + var testClass = GetTypeDefinition(typeof(PropertyTest)); + IProperty p = testClass.Properties.Single(pr => pr.Name == "PropertyWithPrivateSetter"); + Assert.IsTrue(p.CanGet); + Assert.IsTrue(p.CanSet); + Assert.AreEqual(Accessibility.Public, p.Accessibility); + Assert.AreEqual(Accessibility.Public, p.Getter.Accessibility); + Assert.AreEqual(Accessibility.Private, p.Setter.Accessibility); + Assert.IsTrue(p.Getter.HasBody); + } + + [Test] + public void PropertyWithPrivateGetter() + { + var testClass = GetTypeDefinition(typeof(PropertyTest)); + IProperty p = testClass.Properties.Single(pr => pr.Name == "PropertyWithPrivateGetter"); + Assert.IsTrue(p.CanGet); + Assert.IsTrue(p.CanSet); + Assert.AreEqual(Accessibility.Public, p.Accessibility); + Assert.AreEqual(Accessibility.Private, p.Getter.Accessibility); + Assert.AreEqual(Accessibility.Public, p.Setter.Accessibility); + Assert.IsTrue(p.Getter.HasBody); + } + + [Test] + public void PropertyWithoutSetter() + { + var testClass = GetTypeDefinition(typeof(PropertyTest)); + IProperty p = testClass.Properties.Single(pr => pr.Name == "PropertyWithoutSetter"); + Assert.IsTrue(p.CanGet); + Assert.IsFalse(p.CanSet); + Assert.AreEqual(Accessibility.Public, p.Accessibility); + Assert.AreEqual(Accessibility.Public, p.Getter.Accessibility); + Assert.IsNull(p.Setter); + } + + [Test] + public void Indexer() + { + var testClass = GetTypeDefinition(typeof(PropertyTest)); + IProperty p = testClass.Properties.Single(pr => pr.IsIndexer); + Assert.AreEqual("Item", p.Name); + Assert.AreEqual(new[] { "index" }, p.Parameters.Select(x => x.Name).ToArray()); + } + + [Test] + public void IndexerGetter() + { + var testClass = GetTypeDefinition(typeof(PropertyTest)); + IProperty p = testClass.Properties.Single(pr => pr.IsIndexer); + Assert.IsTrue(p.CanGet); + Assert.AreEqual(SymbolKind.Accessor, p.Getter.SymbolKind); + Assert.AreEqual("get_Item", p.Getter.Name); + Assert.AreEqual(Accessibility.Public, p.Getter.Accessibility); + Assert.AreEqual(new[] { "index" }, p.Getter.Parameters.Select(x => x.Name).ToArray()); + Assert.AreEqual("System.String", p.Getter.ReturnType.ReflectionName); + Assert.AreEqual(p, p.Getter.AccessorOwner); + } + + [Test] + public void IndexerSetter() + { + var testClass = GetTypeDefinition(typeof(PropertyTest)); + IProperty p = testClass.Properties.Single(pr => pr.IsIndexer); + Assert.IsTrue(p.CanSet); + Assert.AreEqual(SymbolKind.Accessor, p.Setter.SymbolKind); + Assert.AreEqual("set_Item", p.Setter.Name); + Assert.AreEqual(Accessibility.Public, p.Setter.Accessibility); + Assert.AreEqual(new[] { "index", "value" }, p.Setter.Parameters.Select(x => x.Name).ToArray()); + Assert.AreEqual(TypeKind.Void, p.Setter.ReturnType.Kind); + } + + [Test] + public void GenericPropertyGetter() + { + var type = compilation.FindType(typeof(GenericClass)); + var prop = type.GetProperties(p => p.Name == "Property").Single(); + Assert.AreEqual("System.String", prop.Getter.ReturnType.ReflectionName); + Assert.IsTrue(prop.Getter.IsAccessor); + Assert.AreEqual(prop, prop.Getter.AccessorOwner); + } + + [Test] + public void EnumTest() + { + var e = GetTypeDefinition(typeof(MyEnum)); + Assert.AreEqual(TypeKind.Enum, e.Kind); + Assert.AreEqual(false, e.IsReferenceType); + Assert.AreEqual("System.Int16", e.EnumUnderlyingType.ReflectionName); + Assert.AreEqual(new[] { "System.Enum" }, e.DirectBaseTypes.Select(t => t.ReflectionName).ToArray()); + } + + [Test] + public void EnumFieldsTest() + { + var e = GetTypeDefinition(typeof(MyEnum)); + IField[] fields = e.Fields.ToArray(); + Assert.AreEqual(5, fields.Length); + + foreach (IField f in fields) { + Assert.IsTrue(f.IsStatic); + Assert.IsTrue(f.IsConst); + Assert.AreEqual(Accessibility.Public, f.Accessibility); + Assert.AreSame(e, f.Type); + Assert.AreEqual(typeof(short), f.ConstantValue.GetType()); + } + + Assert.AreEqual("First", fields[0].Name); + Assert.AreEqual(0, fields[0].ConstantValue); + + Assert.AreEqual("Second", fields[1].Name); + Assert.AreSame(e, fields[1].Type); + Assert.AreEqual(1, fields[1].ConstantValue); + + Assert.AreEqual("Flag1", fields[2].Name); + Assert.AreEqual(0x10, fields[2].ConstantValue); + + Assert.AreEqual("Flag2", fields[3].Name); + Assert.AreEqual(0x20, fields[3].ConstantValue); + + Assert.AreEqual("CombinedFlags", fields[4].Name); + Assert.AreEqual(0x30, fields[4].ConstantValue); + } + + [Test] + public void GetNestedTypesFromBaseClassTest() + { + ITypeDefinition d = GetTypeDefinition(typeof(Derived<,>)); + + IType pBase = d.DirectBaseTypes.Single(); + Assert.AreEqual(typeof(Base<>).FullName + "[[`1]]", pBase.ReflectionName); + // Base[`1].GetNestedTypes() = { Base`1+Nested`1[`1, unbound] } + Assert.AreEqual(new[] { typeof(Base<>.Nested<>).FullName + "[[`1],[]]" }, + pBase.GetNestedTypes().Select(n => n.ReflectionName).ToArray()); + + // Derived.GetNestedTypes() = { Base`1+Nested`1[`1, unbound] } + Assert.AreEqual(new[] { typeof(Base<>.Nested<>).FullName + "[[`1],[]]" }, + d.GetNestedTypes().Select(n => n.ReflectionName).ToArray()); + // This is 'leaking' the type parameter from B as is usual when retrieving any members from an unbound type. + } + + [Test] + public void ParameterizedTypeGetNestedTypesFromBaseClassTest() + { + // Derived[string,int].GetNestedTypes() = { Base`1+Nested`1[int, unbound] } + var d = compilation.FindType(typeof(Derived)); + Assert.AreEqual(new[] { typeof(Base<>.Nested<>).FullName + "[[System.Int32],[]]" }, + d.GetNestedTypes().Select(n => n.ReflectionName).ToArray()); + } + + [Test] + public void ConstraintsOnOverrideAreInherited() + { + ITypeDefinition d = GetTypeDefinition(typeof(Derived<,>)); + ITypeParameter tp = d.Methods.Single(m => m.Name == "GenericMethodWithConstraints").TypeParameters.Single(); + Assert.AreEqual("Y", tp.Name); + Assert.IsFalse(tp.HasValueTypeConstraint); + Assert.IsFalse(tp.HasReferenceTypeConstraint); + Assert.IsTrue(tp.HasDefaultConstructorConstraint); + Assert.AreEqual(new string[] { "System.Collections.Generic.IComparer`1[[`1]]", "System.Object" }, + tp.DirectBaseTypes.Select(t => t.ReflectionName).ToArray()); + } + + [Test] + public void DefaultConstructorAddedToStruct() + { + var ctors = compilation.FindType(typeof(MyStructWithCtor)).GetConstructors(); + Assert.AreEqual(2, ctors.Count()); + Assert.IsFalse(ctors.Any(c => c.IsStatic)); + Assert.IsTrue(ctors.All(c => c.ReturnType.Kind == TypeKind.Void)); + Assert.IsTrue(ctors.All(c => c.Accessibility == Accessibility.Public)); + } + + [Test] + public void NoDefaultConstructorAddedToClass() + { + var ctors = compilation.FindType(typeof(MyClassWithCtor)).GetConstructors(); + Assert.AreEqual(Accessibility.Private, ctors.Single().Accessibility); + Assert.AreEqual(1, ctors.Single().Parameters.Count); + } + + [Test] + public void DefaultConstructorOnAbstractClassIsProtected() + { + var ctors = compilation.FindType(typeof(AbstractClass)).GetConstructors(); + Assert.AreEqual(0, ctors.Single().Parameters.Count); + Assert.AreEqual(Accessibility.Protected, ctors.Single().Accessibility); + } + + [Test] + public void SerializableAttribute() + { + IAttribute attr = GetTypeDefinition(typeof(NonCustomAttributes)).Attributes.Single(); + Assert.AreEqual("System.SerializableAttribute", attr.AttributeType.FullName); + } + + [Test] + public void NonSerializedAttribute() + { + IField field = GetTypeDefinition(typeof(NonCustomAttributes)).Fields.Single(f => f.Name == "NonSerializedField"); + Assert.AreEqual("System.NonSerializedAttribute", field.Attributes.Single().AttributeType.FullName); + } + + [Test] + public void ExplicitStructLayoutAttribute() + { + IAttribute attr = GetTypeDefinition(typeof(ExplicitFieldLayoutStruct)).Attributes.Single(); + Assert.AreEqual("System.Runtime.InteropServices.StructLayoutAttribute", attr.AttributeType.FullName); + ResolveResult arg1 = attr.PositionalArguments.Single(); + Assert.AreEqual("System.Runtime.InteropServices.LayoutKind", arg1.Type.FullName); + Assert.AreEqual((int)LayoutKind.Explicit, arg1.ConstantValue); + + var arg2 = attr.NamedArguments[0]; + Assert.AreEqual("CharSet", arg2.Key.Name); + Assert.AreEqual("System.Runtime.InteropServices.CharSet", arg2.Value.Type.FullName); + Assert.AreEqual((int)CharSet.Unicode, arg2.Value.ConstantValue); + + var arg3 = attr.NamedArguments[1]; + Assert.AreEqual("Pack", arg3.Key.Name); + Assert.AreEqual("System.Int32", arg3.Value.Type.FullName); + Assert.AreEqual(8, arg3.Value.ConstantValue); + } + + [Test] + public void FieldOffsetAttribute() + { + IField field = GetTypeDefinition(typeof(ExplicitFieldLayoutStruct)).Fields.Single(f => f.Name == "Field0"); + Assert.AreEqual("System.Runtime.InteropServices.FieldOffsetAttribute", field.Attributes.Single().AttributeType.FullName); + ResolveResult arg = field.Attributes.Single().PositionalArguments.Single(); + Assert.AreEqual("System.Int32", arg.Type.FullName); + Assert.AreEqual(0, arg.ConstantValue); + + field = GetTypeDefinition(typeof(ExplicitFieldLayoutStruct)).Fields.Single(f => f.Name == "Field100"); + Assert.AreEqual("System.Runtime.InteropServices.FieldOffsetAttribute", field.Attributes.Single().AttributeType.FullName); + arg = field.Attributes.Single().PositionalArguments.Single(); + Assert.AreEqual("System.Int32", arg.Type.FullName); + Assert.AreEqual(100, arg.ConstantValue); + } + + [Test] + public void DllImportAttribute() + { + IMethod method = GetTypeDefinition(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod"); + IAttribute dllImport = method.Attributes.Single(); + Assert.AreEqual("System.Runtime.InteropServices.DllImportAttribute", dllImport.AttributeType.FullName); + Assert.AreEqual("unmanaged.dll", dllImport.PositionalArguments[0].ConstantValue); + Assert.AreEqual((int)CharSet.Unicode, dllImport.NamedArguments.Single().Value.ConstantValue); + } + + [Test] + public void InOutParametersOnRefMethod() + { + IParameter p = GetTypeDefinition(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod").Parameters.Single(); + Assert.IsTrue(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.AreEqual(2, p.Attributes.Count); + Assert.AreEqual("System.Runtime.InteropServices.InAttribute", p.Attributes[0].AttributeType.FullName); + Assert.AreEqual("System.Runtime.InteropServices.OutAttribute", p.Attributes[1].AttributeType.FullName); + } + + [Test] + public void MarshalAsAttributeOnMethod() + { + IMethod method = GetTypeDefinition(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod"); + IAttribute marshalAs = method.ReturnTypeAttributes.Single(); + Assert.AreEqual((int)UnmanagedType.Bool, marshalAs.PositionalArguments.Single().ConstantValue); + } + + [Test] + public void MethodWithOutParameter() + { + IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOutParameter").Parameters.Single(); + Assert.IsFalse(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsTrue(p.IsOut); + Assert.AreEqual(0, p.Attributes.Count); + Assert.IsTrue(p.Type.Kind == TypeKind.ByReference); + } + + [Test] + public void MethodWithParamsArray() + { + IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithParamsArray").Parameters.Single(); + Assert.IsFalse(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.IsTrue(p.IsParams); + Assert.AreEqual(0, p.Attributes.Count); + Assert.IsTrue(p.Type.Kind == TypeKind.Array); + } + + [Test] + public void MethodWithOptionalParameter() + { + IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalParameter").Parameters.Single(); + Assert.IsTrue(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.IsFalse(p.IsParams); + Assert.AreEqual(0, p.Attributes.Count); + Assert.AreEqual(4, p.ConstantValue); + } + + [Test] + public void MethodWithExplicitOptionalParameter() + { + IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithExplicitOptionalParameter").Parameters.Single(); + Assert.IsTrue(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.IsFalse(p.IsParams); + // explicit optional parameter appears in type system if it's read from C#, but not when read from IL + //Assert.AreEqual(1, p.Attributes.Count); + } + + [Test] + public void MethodWithEnumOptionalParameter() + { + IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithEnumOptionalParameter").Parameters.Single(); + Assert.IsTrue(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.IsFalse(p.IsParams); + Assert.AreEqual(0, p.Attributes.Count); + Assert.AreEqual((int)StringComparison.OrdinalIgnoreCase, p.ConstantValue); + } + + [Test] + public void MethodWithOptionalNullableParameter() + { + IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalNullableParameter").Parameters.Single(); + Assert.IsTrue(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.IsFalse(p.IsParams); + Assert.AreEqual(0, p.Attributes.Count); + Assert.IsNull(p.ConstantValue); + } + + [Test] + public void MethodWithOptionalLongParameter() + { + IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalLongParameter").Parameters.Single(); + Assert.IsTrue(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.IsFalse(p.IsParams); + Assert.AreEqual(1L, p.ConstantValue); + Assert.AreEqual(typeof(long), p.ConstantValue.GetType()); + } + + [Test] + public void MethodWithOptionalNullableLongParameter() + { + IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalNullableLongParameter").Parameters.Single(); + Assert.IsTrue(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.IsFalse(p.IsParams); + Assert.AreEqual(1L, p.ConstantValue); + Assert.AreEqual(typeof(long), p.ConstantValue.GetType()); + } + + [Test] + public void VarArgsMethod() + { + IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "VarArgsMethod").Parameters.Single(); + Assert.IsFalse(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.IsFalse(p.IsParams); + Assert.AreEqual(TypeKind.ArgList, p.Type.Kind); + Assert.AreEqual("", p.Name); + } + + [Test] + public void VarArgsCtor() + { + IParameter p = GetTypeDefinition(typeof(VarArgsCtor)).Methods.Single(m => m.IsConstructor).Parameters.Single(); + Assert.IsFalse(p.IsOptional); + Assert.IsFalse(p.IsRef); + Assert.IsFalse(p.IsOut); + Assert.IsFalse(p.IsParams); + Assert.AreEqual(TypeKind.ArgList, p.Type.Kind); + Assert.AreEqual("", p.Name); + } + + [Test] + public void GenericDelegate_Variance() + { + ITypeDefinition type = GetTypeDefinition(typeof(GenericDelegate<,>)); + Assert.AreEqual(VarianceModifier.Contravariant, type.TypeParameters[0].Variance); + Assert.AreEqual(VarianceModifier.Covariant, type.TypeParameters[1].Variance); + + Assert.AreSame(type.TypeParameters[1], type.TypeParameters[0].DirectBaseTypes.FirstOrDefault()); + } + + [Test] + public void GenericDelegate_ReferenceTypeConstraints() + { + ITypeDefinition type = GetTypeDefinition(typeof(GenericDelegate<,>)); + Assert.IsFalse(type.TypeParameters[0].HasReferenceTypeConstraint); + Assert.IsTrue(type.TypeParameters[1].HasReferenceTypeConstraint); + + Assert.IsNull(type.TypeParameters[0].IsReferenceType); + Assert.AreEqual(true, type.TypeParameters[1].IsReferenceType); + } + + [Test] + public void GenericDelegate_GetInvokeMethod() + { + IType type = compilation.FindType(typeof(GenericDelegate)); + IMethod m = type.GetDelegateInvokeMethod(); + Assert.AreEqual("Invoke", m.Name); + Assert.AreEqual("System.Object", m.ReturnType.FullName); + Assert.AreEqual("System.String", m.Parameters[0].Type.FullName); + } + + [Test] + public void ComInterfaceTest() + { + ITypeDefinition type = GetTypeDefinition(typeof(IAssemblyEnum)); + // [ComImport] + Assert.AreEqual(1, type.Attributes.Count(a => a.AttributeType.FullName == typeof(ComImportAttribute).FullName)); + + IMethod m = type.Methods.Single(); + Assert.AreEqual("GetNextAssembly", m.Name); + Assert.AreEqual(Accessibility.Public, m.Accessibility); + Assert.IsTrue(m.IsAbstract); + Assert.IsFalse(m.IsVirtual); + Assert.IsFalse(m.IsSealed); + } + + [Test] + public void InnerClassInGenericClassIsReferencedUsingParameterizedType() + { + ITypeDefinition type = GetTypeDefinition(typeof(OuterGeneric<>)); + IField field1 = type.Fields.Single(f => f.Name == "Field1"); + IField field2 = type.Fields.Single(f => f.Name == "Field2"); + IField field3 = type.Fields.Single(f => f.Name == "Field3"); + + // types must be self-parameterized + Assert.AreEqual("ICSharpCode.Decompiler.Tests.TypeSystem.OuterGeneric`1+Inner[[`0]]", field1.Type.ReflectionName); + Assert.AreEqual("ICSharpCode.Decompiler.Tests.TypeSystem.OuterGeneric`1+Inner[[`0]]", field2.Type.ReflectionName); + Assert.AreEqual("ICSharpCode.Decompiler.Tests.TypeSystem.OuterGeneric`1+Inner[[ICSharpCode.Decompiler.Tests.TypeSystem.OuterGeneric`1+Inner[[`0]]]]", field3.Type.ReflectionName); + } + + [Test] + public void FlagsOnInterfaceMembersAreCorrect() + { + ITypeDefinition type = GetTypeDefinition(typeof(IInterfaceWithProperty)); + var p = type.Properties.Single(); + Assert.AreEqual(false, p.IsIndexer); + Assert.AreEqual(true, p.IsAbstract); + Assert.AreEqual(true, p.IsOverridable); + Assert.AreEqual(false, p.IsOverride); + Assert.AreEqual(true, p.IsPublic); + Assert.AreEqual(true, p.Getter.IsAbstract); + Assert.AreEqual(true, p.Getter.IsOverridable); + Assert.AreEqual(false, p.Getter.IsOverride); + Assert.AreEqual(true, p.Getter.IsPublic); + Assert.AreEqual(false, p.Getter.HasBody); + Assert.AreEqual(true, p.Setter.IsAbstract); + Assert.AreEqual(true, p.Setter.IsOverridable); + Assert.AreEqual(false, p.Setter.IsOverride); + Assert.AreEqual(true, p.Setter.IsPublic); + Assert.AreEqual(false, p.Setter.HasBody); + + type = GetTypeDefinition(typeof(IInterfaceWithIndexers)); + p = type.Properties.Single(x => x.Parameters.Count == 2); + Assert.AreEqual(true, p.IsIndexer); + Assert.AreEqual(true, p.IsAbstract); + Assert.AreEqual(true, p.IsOverridable); + Assert.AreEqual(false, p.IsOverride); + Assert.AreEqual(true, p.IsPublic); + Assert.AreEqual(true, p.Getter.IsAbstract); + Assert.AreEqual(true, p.Getter.IsOverridable); + Assert.AreEqual(false, p.Getter.IsOverride); + Assert.AreEqual(true, p.Getter.IsPublic); + Assert.AreEqual(true, p.Setter.IsAbstract); + Assert.AreEqual(true, p.Setter.IsOverridable); + Assert.AreEqual(false, p.Setter.IsOverride); + Assert.AreEqual(true, p.Setter.IsPublic); + + type = GetTypeDefinition(typeof(IHasEvent)); + var e = type.Events.Single(); + Assert.AreEqual(true, e.IsAbstract); + Assert.AreEqual(true, e.IsOverridable); + Assert.AreEqual(false, e.IsOverride); + Assert.AreEqual(true, e.IsPublic); + Assert.AreEqual(true, e.AddAccessor.IsAbstract); + Assert.AreEqual(true, e.AddAccessor.IsOverridable); + Assert.AreEqual(false, e.AddAccessor.IsOverride); + Assert.AreEqual(true, e.AddAccessor.IsPublic); + Assert.AreEqual(true, e.RemoveAccessor.IsAbstract); + Assert.AreEqual(true, e.RemoveAccessor.IsOverridable); + Assert.AreEqual(false, e.RemoveAccessor.IsOverride); + Assert.AreEqual(true, e.RemoveAccessor.IsPublic); + + type = GetTypeDefinition(typeof(IDisposable)); + var m = type.Methods.Single(); + Assert.AreEqual(true, m.IsAbstract); + Assert.AreEqual(true, m.IsOverridable); + Assert.AreEqual(false, m.IsOverride); + Assert.AreEqual(true, m.IsPublic); + } + + [Test] + public void InnerClassInGenericClass_TypeParameterOwner() + { + ITypeDefinition type = GetTypeDefinition(typeof(OuterGeneric<>.Inner)); + Assert.AreSame(type.DeclaringTypeDefinition.TypeParameters[0], type.TypeParameters[0]); + Assert.AreSame(type.DeclaringTypeDefinition, type.TypeParameters[0].Owner); + } + + [Test] + public void InnerClassInGenericClass_ReferencesTheOuterClass_Field() + { + ITypeDefinition type = GetTypeDefinition(typeof(OuterGeneric<>.Inner)); + IField f = type.Fields.Single(); + Assert.AreEqual("ICSharpCode.Decompiler.Tests.TypeSystem.OuterGeneric`1[[`0]]", f.Type.ReflectionName); + } + + [Test] + public void InnerClassInGenericClass_ReferencesTheOuterClass_Parameter() + { + ITypeDefinition type = GetTypeDefinition(typeof(OuterGeneric<>.Inner)); + IParameter p = type.Methods.Single(m => m.IsConstructor).Parameters.Single(); + Assert.AreEqual("ICSharpCode.Decompiler.Tests.TypeSystem.OuterGeneric`1[[`0]]", p.Type.ReflectionName); + } + + ResolveResult GetParamsAttributeArgument(int index) + { + ITypeDefinition type = GetTypeDefinition(typeof(ParamsAttribute)); + var arr = (ArrayCreateResolveResult)type.Attributes.Single().PositionalArguments.Single(); + Assert.AreEqual(5, arr.InitializerElements.Count); + Assert.AreEqual(1, arr.SizeArguments.Count); + Assert.AreEqual(5, arr.SizeArguments[0].ConstantValue); + return arr.InitializerElements[index]; + } + + ResolveResult Unbox(ResolveResult resolveResult) + { + ConversionResolveResult crr = (ConversionResolveResult)resolveResult; + Assert.AreEqual(TypeKind.Class, crr.Type.Kind); + Assert.AreEqual("System.Object", crr.Type.FullName); + Assert.AreEqual(Conversion.BoxingConversion, crr.Conversion); + return crr.Input; + } + + [Test] + public void ParamsAttribute_Integer() + { + ResolveResult rr = Unbox(GetParamsAttributeArgument(0)); + Assert.AreEqual("System.Int32", rr.Type.FullName); + Assert.AreEqual(1, rr.ConstantValue); + } + + [Test] + public void ParamsAttribute_Enum() + { + ResolveResult rr = Unbox(GetParamsAttributeArgument(1)); + Assert.AreEqual("System.StringComparison", rr.Type.FullName); + Assert.AreEqual((int)StringComparison.CurrentCulture, rr.ConstantValue); + } + + [Test] + public void ParamsAttribute_NullReference() + { + ResolveResult rr = GetParamsAttributeArgument(2); + Assert.AreEqual("System.Object", rr.Type.FullName); + Assert.IsTrue(rr.IsCompileTimeConstant); + Assert.IsNull(rr.ConstantValue); + } + + [Test] + public void ParamsAttribute_Double() + { + ResolveResult rr = Unbox(GetParamsAttributeArgument(3)); + Assert.AreEqual("System.Double", rr.Type.FullName); + Assert.AreEqual(4.0, rr.ConstantValue); + } + + [Test] + public void ParamsAttribute_String() + { + ConversionResolveResult rr = (ConversionResolveResult)GetParamsAttributeArgument(4); + Assert.AreEqual("System.Object", rr.Type.FullName); + Assert.AreEqual("System.String", rr.Input.Type.FullName); + Assert.AreEqual("Test", rr.Input.ConstantValue); + } + + [Test] + public void ParamsAttribute_Property() + { + ITypeDefinition type = GetTypeDefinition(typeof(ParamsAttribute)); + IProperty prop = type.Properties.Single(p => p.Name == "Property"); + var attr = prop.Attributes.Single(); + Assert.AreEqual(type, attr.AttributeType); + + var normalArguments = ((ArrayCreateResolveResult)attr.PositionalArguments.Single()).InitializerElements; + Assert.AreEqual(0, normalArguments.Count); + + var namedArg = attr.NamedArguments.Single(); + Assert.AreEqual(prop, namedArg.Key); + var arrayElements = ((ArrayCreateResolveResult)namedArg.Value).InitializerElements; + Assert.AreEqual(2, arrayElements.Count); + } + + [Test] + public void ParamsAttribute_Getter_ReturnType() + { + ITypeDefinition type = GetTypeDefinition(typeof(ParamsAttribute)); + IProperty prop = type.Properties.Single(p => p.Name == "Property"); + Assert.AreEqual(0, prop.Getter.Attributes.Count); + Assert.AreEqual(1, prop.Getter.ReturnTypeAttributes.Count); + } + + [Test] + public void DoubleAttribute_ImplicitNumericConversion() + { + ITypeDefinition type = GetTypeDefinition(typeof(DoubleAttribute)); + var arg = type.Attributes.Single().PositionalArguments.ElementAt(0); + Assert.AreEqual("System.Double", arg.Type.ReflectionName); + Assert.AreEqual(1.0, arg.ConstantValue); + } + + [Test] + public void ImplicitImplementationOfUnifiedMethods() + { + ITypeDefinition type = GetTypeDefinition(typeof(ImplementationOfUnifiedMethods)); + IMethod test = type.Methods.Single(m => m.Name == "Test"); + Assert.AreEqual(2, test.ImplementedInterfaceMembers.Count); + Assert.AreEqual("Int32", ((IMethod)test.ImplementedInterfaceMembers[0]).Parameters.Single().Type.Name); + Assert.AreEqual("Int32", ((IMethod)test.ImplementedInterfaceMembers[1]).Parameters.Single().Type.Name); + Assert.AreEqual("T", ((IMethod)test.ImplementedInterfaceMembers[0].MemberDefinition).Parameters.Single().Type.Name); + Assert.AreEqual("S", ((IMethod)test.ImplementedInterfaceMembers[1].MemberDefinition).Parameters.Single().Type.Name); + } + + [Test] + public void StaticityOfEventAccessors() + { + // https://github.com/icsharpcode/NRefactory/issues/20 + ITypeDefinition type = GetTypeDefinition(typeof(ClassWithStaticAndNonStaticMembers)); + var evt1 = type.Events.Single(e => e.Name == "Event1"); + Assert.IsTrue(evt1.IsStatic); + Assert.IsTrue(evt1.AddAccessor.IsStatic); + Assert.IsTrue(evt1.RemoveAccessor.IsStatic); + + var evt2 = type.Events.Single(e => e.Name == "Event2"); + Assert.IsFalse(evt2.IsStatic); + Assert.IsFalse(evt2.AddAccessor.IsStatic); + Assert.IsFalse(evt2.RemoveAccessor.IsStatic); + + var evt3 = type.Events.Single(e => e.Name == "Event3"); + Assert.IsTrue(evt3.IsStatic); + Assert.IsTrue(evt3.AddAccessor.IsStatic); + Assert.IsTrue(evt3.RemoveAccessor.IsStatic); + + var evt4 = type.Events.Single(e => e.Name == "Event4"); + Assert.IsFalse(evt4.IsStatic); + Assert.IsFalse(evt4.AddAccessor.IsStatic); + Assert.IsFalse(evt4.RemoveAccessor.IsStatic); + } + + [Test] + public void StaticityOfPropertyAccessors() + { + // https://github.com/icsharpcode/NRefactory/issues/20 + ITypeDefinition type = GetTypeDefinition(typeof(ClassWithStaticAndNonStaticMembers)); + var prop1 = type.Properties.Single(e => e.Name == "Prop1"); + Assert.IsTrue(prop1.IsStatic); + Assert.IsTrue(prop1.Getter.IsStatic); + Assert.IsTrue(prop1.Setter.IsStatic); + + var prop2 = type.Properties.Single(e => e.Name == "Prop2"); + Assert.IsFalse(prop2.IsStatic); + Assert.IsFalse(prop2.Getter.IsStatic); + Assert.IsFalse(prop2.Setter.IsStatic); + + var prop3 = type.Properties.Single(e => e.Name == "Prop3"); + Assert.IsTrue(prop3.IsStatic); + Assert.IsTrue(prop3.Getter.IsStatic); + Assert.IsTrue(prop3.Setter.IsStatic); + + var prop4 = type.Properties.Single(e => e.Name == "Prop4"); + Assert.IsFalse(prop4.IsStatic); + Assert.IsFalse(prop4.Getter.IsStatic); + Assert.IsFalse(prop4.Setter.IsStatic); + } + + [Test] + public void PropertyAccessorsHaveBody() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassWithStaticAndNonStaticMembers)); + foreach (var prop in type.Properties) { + Assert.IsTrue(prop.Getter.HasBody, prop.Getter.Name); + Assert.IsTrue(prop.Setter.HasBody, prop.Setter.Name); + } + } + + [Test] + public void EventAccessorNames() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassWithStaticAndNonStaticMembers)); + var customEvent = type.Events.Single(e => e.Name == "Event1"); + Assert.AreEqual("add_Event1", customEvent.AddAccessor.Name); + Assert.AreEqual("remove_Event1", customEvent.RemoveAccessor.Name); + + var normalEvent = type.Events.Single(e => e.Name == "Event3"); + Assert.AreEqual("add_Event3", normalEvent.AddAccessor.Name); + Assert.AreEqual("remove_Event3", normalEvent.RemoveAccessor.Name); + } + + [Test] + public void EventAccessorHaveBody() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassWithStaticAndNonStaticMembers)); + foreach (var ev in type.Events) { + Assert.IsTrue(ev.AddAccessor.HasBody, ev.AddAccessor.Name); + Assert.IsTrue(ev.RemoveAccessor.HasBody, ev.RemoveAccessor.Name); + } + } + + [Test] + public void InterfacePropertyAccessorsShouldNotBeOverrides() + { + ITypeDefinition type = GetTypeDefinition(typeof(IInterfaceWithProperty)); + var prop = type.Properties.Single(p => p.Name == "Prop"); + Assert.That(prop.Getter.IsOverride, Is.False); + Assert.That(prop.Getter.IsOverridable, Is.True); + Assert.That(prop.Setter.IsOverride, Is.False); + Assert.That(prop.Setter.IsOverridable, Is.True); + } + + [Test] + public void VirtualPropertyAccessorsShouldNotBeOverrides() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassWithVirtualProperty)); + var prop = type.Properties.Single(p => p.Name == "Prop"); + Assert.That(prop.Getter.IsOverride, Is.False); + Assert.That(prop.Getter.IsOverridable, Is.True); + Assert.That(prop.Setter.IsOverride, Is.False); + Assert.That(prop.Setter.IsOverridable, Is.True); + } + + [Test] + public void ClassThatOverridesGetterOnly() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatOverridesGetterOnly)); + var prop = type.Properties.Single(p => p.Name == "Prop"); + Assert.AreEqual(Accessibility.Public, prop.Accessibility); + Assert.AreEqual(Accessibility.Public, prop.Getter.Accessibility); + } + + [Test] + public void ClassThatOverridesSetterOnly() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatOverridesSetterOnly)); + var prop = type.Properties.Single(p => p.Name == "Prop"); + Assert.AreEqual(Accessibility.Public, prop.Accessibility); + Assert.AreEqual(Accessibility.Protected, prop.Setter.Accessibility); + } + + [Test] + public void PropertyAccessorsShouldBeReportedAsImplementingInterfaceAccessors() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsProperty)); + var prop = type.Properties.Single(p => p.Name == "Prop"); + Assert.That(prop.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithProperty.Prop" })); + Assert.That(prop.Getter.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithProperty.get_Prop" })); + Assert.That(prop.Setter.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithProperty.set_Prop" })); + } + + [Test] + public void PropertyThatImplementsInterfaceIsNotVirtual() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsProperty)); + var prop = type.Properties.Single(p => p.Name == "Prop"); + Assert.IsFalse(prop.IsVirtual); + Assert.IsFalse(prop.IsOverridable); + Assert.IsFalse(prop.IsSealed); + } + + [Test] + public void Property_SealedOverride() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatOverridesAndSealsVirtualProperty)); + var prop = type.Properties.Single(p => p.Name == "Prop"); + Assert.IsFalse(prop.IsVirtual); + Assert.IsTrue(prop.IsOverride); + Assert.IsTrue(prop.IsSealed); + Assert.IsFalse(prop.IsOverridable); + } + + [Test] + public void IndexerAccessorsShouldBeReportedAsImplementingTheCorrectInterfaceAccessors() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsIndexers)); + var ix1 = type.Properties.Single(p => p.Parameters.Count == 1 && p.Parameters[0].Type.GetDefinition().KnownTypeCode == KnownTypeCode.Int32); + var ix2 = type.Properties.Single(p => p.Parameters.Count == 1 && p.Parameters[0].Type.GetDefinition().KnownTypeCode == KnownTypeCode.String); + var ix3 = type.Properties.Single(p => p.Parameters.Count == 2); + + Assert.That(ix1.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EquivalentTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithIndexers.Item", "ICSharpCode.Decompiler.Tests.TypeSystem.IGenericInterfaceWithIndexer`1.Item" })); + Assert.That(ix1.ImplementedInterfaceMembers.All(p => ((IProperty)p).Parameters.Select(x => x.Type.GetDefinition().KnownTypeCode).SequenceEqual(new[] { KnownTypeCode.Int32 }))); + Assert.That(ix1.Getter.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EquivalentTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithIndexers.get_Item", "ICSharpCode.Decompiler.Tests.TypeSystem.IGenericInterfaceWithIndexer`1.get_Item" })); + Assert.That(ix1.Getter.ImplementedInterfaceMembers.All(m => ((IMethod)m).Parameters.Select(p => p.Type.GetDefinition().KnownTypeCode).SequenceEqual(new[] { KnownTypeCode.Int32 }))); + Assert.That(ix1.Setter.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EquivalentTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithIndexers.set_Item", "ICSharpCode.Decompiler.Tests.TypeSystem.IGenericInterfaceWithIndexer`1.set_Item" })); + Assert.That(ix1.Setter.ImplementedInterfaceMembers.All(m => ((IMethod)m).Parameters.Select(p => p.Type.GetDefinition().KnownTypeCode).SequenceEqual(new[] { KnownTypeCode.Int32, KnownTypeCode.Int32 }))); + + Assert.That(ix2.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithIndexers.Item" })); + Assert.That(ix2.ImplementedInterfaceMembers.All(p => ((IProperty)p).Parameters.Select(x => x.Type.GetDefinition().KnownTypeCode).SequenceEqual(new[] { KnownTypeCode.String }))); + Assert.That(ix2.Getter.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithIndexers.get_Item" })); + Assert.That(ix2.Getter.ImplementedInterfaceMembers.All(m => ((IMethod)m).Parameters.Select(p => p.Type.GetDefinition().KnownTypeCode).SequenceEqual(new[] { KnownTypeCode.String }))); + Assert.That(ix2.Setter.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithIndexers.set_Item" })); + Assert.That(ix2.Setter.ImplementedInterfaceMembers.All(m => ((IMethod)m).Parameters.Select(p => p.Type.GetDefinition().KnownTypeCode).SequenceEqual(new[] { KnownTypeCode.String, KnownTypeCode.Int32 }))); + + Assert.That(ix3.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithIndexers.Item" })); + Assert.That(ix3.ImplementedInterfaceMembers.All(p => ((IProperty)p).Parameters.Select(x => x.Type.GetDefinition().KnownTypeCode).SequenceEqual(new[] { KnownTypeCode.Int32, KnownTypeCode.Int32 }))); + Assert.That(ix3.Getter.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithIndexers.get_Item" })); + Assert.That(ix3.Getter.ImplementedInterfaceMembers.All(m => ((IMethod)m).Parameters.Select(p => p.Type.GetDefinition().KnownTypeCode).SequenceEqual(new[] { KnownTypeCode.Int32, KnownTypeCode.Int32 }))); + Assert.That(ix3.Setter.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithIndexers.set_Item" })); + Assert.That(ix3.Setter.ImplementedInterfaceMembers.All(m => ((IMethod)m).Parameters.Select(p => p.Type.GetDefinition().KnownTypeCode).SequenceEqual(new[] { KnownTypeCode.Int32, KnownTypeCode.Int32, KnownTypeCode.Int32 }))); + } + + [Test] + public void ExplicitIndexerImplementationReturnsTheCorrectMembers() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsIndexersExplicitly)); + + Assert.That(type.Properties.All(p => p.SymbolKind == SymbolKind.Indexer)); + Assert.That(type.Properties.All(p => p.ImplementedInterfaceMembers.Count == 1)); + Assert.That(type.Properties.All(p => p.Getter.ImplementedInterfaceMembers.Count == 1)); + Assert.That(type.Properties.All(p => p.Setter.ImplementedInterfaceMembers.Count == 1)); + } + + [Test] + public void ExplicitDisposableImplementation() + { + ITypeDefinition disposable = GetTypeDefinition(typeof(ExplicitDisposableImplementation)); + IMethod method = disposable.Methods.Single(m => !m.IsConstructor); + Assert.IsTrue(method.IsExplicitInterfaceImplementation); + Assert.AreEqual("System.IDisposable.Dispose", method.ImplementedInterfaceMembers.Single().FullName); + } + + [Test] + public void ExplicitImplementationOfUnifiedMethods() + { + IType type = compilation.FindType(typeof(ExplicitGenericInterfaceImplementationWithUnifiableMethods)); + Assert.AreEqual(2, type.GetMethods(m => m.IsExplicitInterfaceImplementation).Count()); + foreach (IMethod method in type.GetMethods(m => m.IsExplicitInterfaceImplementation)) { + Assert.AreEqual(1, method.ImplementedInterfaceMembers.Count, method.ToString()); + Assert.AreEqual("System.Int32", method.Parameters.Single().Type.ReflectionName); + IMethod interfaceMethod = (IMethod)method.ImplementedInterfaceMembers.Single(); + Assert.AreEqual("System.Int32", interfaceMethod.Parameters.Single().Type.ReflectionName); + var genericParamType = ((IMethod)method.MemberDefinition).Parameters.Single().Type; + var interfaceGenericParamType = ((IMethod)interfaceMethod.MemberDefinition).Parameters.Single().Type; + Assert.AreEqual(TypeKind.TypeParameter, genericParamType.Kind); + Assert.AreEqual(TypeKind.TypeParameter, interfaceGenericParamType.Kind); + Assert.AreEqual(genericParamType.ReflectionName, interfaceGenericParamType.ReflectionName); + } + } + + [Test] + public void ExplicitGenericInterfaceImplementation() + { + ITypeDefinition impl = GetTypeDefinition(typeof(ExplicitGenericInterfaceImplementation)); + IType genericInterfaceOfString = compilation.FindType(typeof(IGenericInterface)); + IMethod implMethod1 = impl.Methods.Single(m => !m.IsConstructor && !m.Parameters[1].IsRef); + IMethod implMethod2 = impl.Methods.Single(m => !m.IsConstructor && m.Parameters[1].IsRef); + Assert.IsTrue(implMethod1.IsExplicitInterfaceImplementation); + Assert.IsTrue(implMethod2.IsExplicitInterfaceImplementation); + + IMethod interfaceMethod1 = (IMethod)implMethod1.ImplementedInterfaceMembers.Single(); + Assert.AreEqual(genericInterfaceOfString, interfaceMethod1.DeclaringType); + Assert.IsTrue(!interfaceMethod1.Parameters[1].IsRef); + + IMethod interfaceMethod2 = (IMethod)implMethod2.ImplementedInterfaceMembers.Single(); + Assert.AreEqual(genericInterfaceOfString, interfaceMethod2.DeclaringType); + Assert.IsTrue(interfaceMethod2.Parameters[1].IsRef); + } + + [Test] + public void ExplicitlyImplementedPropertiesShouldBeReportedAsBeingImplemented() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsPropertyExplicitly)); + var prop = type.Properties.Single(); + Assert.That(prop.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithProperty.Prop" })); + Assert.That(prop.Getter.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithProperty.get_Prop" })); + Assert.That(prop.Setter.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IInterfaceWithProperty.set_Prop" })); + } + + [Test] + public void ExplicitlyImplementedPropertiesShouldHaveExplicitlyImplementedAccessors() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsPropertyExplicitly)); + var prop = type.Properties.Single(); + Assert.IsTrue(prop.IsExplicitInterfaceImplementation); + Assert.IsTrue(prop.Getter.IsExplicitInterfaceImplementation); + Assert.IsTrue(prop.Setter.IsExplicitInterfaceImplementation); + } + + [Test] + public void EventAccessorsShouldBeReportedAsImplementingInterfaceAccessors() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsEvent)); + var evt = type.Events.Single(p => p.Name == "Event"); + Assert.That(evt.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IHasEvent.Event" })); + Assert.That(evt.AddAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IHasEvent.add_Event" })); + Assert.That(evt.RemoveAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IHasEvent.remove_Event" })); + } + + [Test] + public void EventAccessorsShouldBeReportedAsImplementingInterfaceAccessorsWhenCustomAccessorMethodsAreUsed() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsEventWithCustomAccessors)); + var evt = type.Events.Single(p => p.Name == "Event"); + Assert.That(evt.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IHasEvent.Event" })); + Assert.That(evt.AddAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IHasEvent.add_Event" })); + Assert.That(evt.RemoveAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IHasEvent.remove_Event" })); + } + + [Test] + public void ExplicitlyImplementedEventsShouldBeReportedAsBeingImplemented() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsEventExplicitly)); + var evt = type.Events.Single(); + Assert.That(evt.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IHasEvent.Event" })); + Assert.That(evt.AddAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IHasEvent.add_Event" })); + Assert.That(evt.RemoveAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.Decompiler.Tests.TypeSystem.IHasEvent.remove_Event" })); + } + + [Test] + public void MembersDeclaredInDerivedInterfacesDoNotImplementBaseMembers() + { + ITypeDefinition type = GetTypeDefinition(typeof(IShadowTestDerived)); + var method = type.Methods.Single(m => m.Name == "Method"); + var indexer = type.Properties.Single(p => p.IsIndexer); + var prop = type.Properties.Single(p => p.Name == "Prop"); + var evt = type.Events.Single(e => e.Name == "Evt"); + + Assert.That(method.ImplementedInterfaceMembers, Is.Empty); + Assert.That(indexer.ImplementedInterfaceMembers, Is.Empty); + Assert.That(indexer.Getter.ImplementedInterfaceMembers, Is.Empty); + Assert.That(indexer.Setter.ImplementedInterfaceMembers, Is.Empty); + Assert.That(prop.ImplementedInterfaceMembers, Is.Empty); + Assert.That(prop.Getter.ImplementedInterfaceMembers, Is.Empty); + Assert.That(prop.Setter.ImplementedInterfaceMembers, Is.Empty); + Assert.That(evt.ImplementedInterfaceMembers, Is.Empty); + Assert.That(evt.AddAccessor.ImplementedInterfaceMembers, Is.Empty); + Assert.That(evt.RemoveAccessor.ImplementedInterfaceMembers, Is.Empty); + } + + [Test] + public void StaticClassTest() + { + ITypeDefinition type = GetTypeDefinition(typeof(StaticClass)); + Assert.IsTrue(type.IsAbstract); + Assert.IsTrue(type.IsSealed); + Assert.IsTrue(type.IsStatic); + } + + [Test] + public void NoDefaultConstructorOnStaticClassTest() + { + ITypeDefinition type = GetTypeDefinition(typeof(StaticClass)); + Assert.AreEqual(0, type.GetConstructors().Count()); + } + + [Test] + public void IndexerNonDefaultName() + { + ITypeDefinition type = GetTypeDefinition(typeof(IndexerNonDefaultName)); + var indexer = type.GetProperties(p => p.IsIndexer).Single(); + Assert.AreEqual("Foo", indexer.Name); + } + + [Test] + public void TestNullableDefaultParameter() + { + ITypeDefinition type = GetTypeDefinition(typeof(ClassWithMethodThatHasNullableDefaultParameter)); + var method = type.GetMethods().Single(m => m.Name == "Foo"); + Assert.AreEqual(42, method.Parameters.Single().ConstantValue); + } + + [Test] + public void AccessibilityTests() + { + ITypeDefinition type = GetTypeDefinition(typeof(AccessibilityTest)); + Assert.AreEqual(Accessibility.Public, type.Methods.Single(m => m.Name == "Public").Accessibility); + Assert.AreEqual(Accessibility.Internal, type.Methods.Single(m => m.Name == "Internal").Accessibility); + Assert.AreEqual(Accessibility.ProtectedOrInternal, type.Methods.Single(m => m.Name == "ProtectedInternal").Accessibility); + Assert.AreEqual(Accessibility.ProtectedOrInternal, type.Methods.Single(m => m.Name == "InternalProtected").Accessibility); + Assert.AreEqual(Accessibility.Protected, type.Methods.Single(m => m.Name == "Protected").Accessibility); + Assert.AreEqual(Accessibility.Private, type.Methods.Single(m => m.Name == "Private").Accessibility); + Assert.AreEqual(Accessibility.Private, type.Methods.Single(m => m.Name == "None").Accessibility); + } + + private void AssertConstantField(ITypeDefinition type, string name, T expected) + { + var f = type.GetFields().Single(x => x.Name == name); + Assert.IsTrue(f.IsConst); + Assert.AreEqual(expected, f.ConstantValue); + } + + [Test] + public unsafe void ConstantFieldsCreatedWithNew() + { + ITypeDefinition type = GetTypeDefinition(typeof(ConstantFieldTest)); + AssertConstantField(type, "CNewb", new byte()); + AssertConstantField(type, "CNewsb", new sbyte()); + AssertConstantField(type, "CNewc", new char()); + AssertConstantField(type, "CNews", new short()); + AssertConstantField(type, "CNewus", new ushort()); + AssertConstantField(type, "CNewi", new int()); + AssertConstantField(type, "CNewui", new uint()); + AssertConstantField(type, "CNewl", new long()); + AssertConstantField(type, "CNewul", new ulong()); + AssertConstantField(type, "CNewd", new double()); + AssertConstantField(type, "CNewf", new float()); + AssertConstantField(type, "CNewm", new decimal()); + } + + + [Test] + public void ConstantFieldsSizeOf() + { + ITypeDefinition type = GetTypeDefinition(typeof(ConstantFieldTest)); + AssertConstantField(type, "SOsb", sizeof(sbyte)); + AssertConstantField(type, "SOb", sizeof(byte)); + AssertConstantField(type, "SOs", sizeof(short)); + AssertConstantField(type, "SOus", sizeof(ushort)); + AssertConstantField(type, "SOi", sizeof(int)); + AssertConstantField(type, "SOui", sizeof(uint)); + AssertConstantField(type, "SOl", sizeof(long)); + AssertConstantField(type, "SOul", sizeof(ulong)); + AssertConstantField(type, "SOc", sizeof(char)); + AssertConstantField(type, "SOf", sizeof(float)); + AssertConstantField(type, "SOd", sizeof(double)); + AssertConstantField(type, "SObl", sizeof(bool)); + AssertConstantField(type, "SOe", sizeof(MyEnum)); + } + + [Test] + public void ConstantEnumFromThisAssembly() + { + ITypeDefinition type = GetTypeDefinition(typeof(ConstantFieldTest)); + IField field = type.Fields.Single(f => f.Name == "EnumFromThisAssembly"); + Assert.IsTrue(field.IsConst); + Assert.AreEqual((short)MyEnum.Second, field.ConstantValue); + } + + [Test] + public void ConstantEnumFromAnotherAssembly() + { + ITypeDefinition type = GetTypeDefinition(typeof(ConstantFieldTest)); + IField field = type.Fields.Single(f => f.Name == "EnumFromAnotherAssembly"); + Assert.IsTrue(field.IsConst); + Assert.AreEqual((int)StringComparison.OrdinalIgnoreCase, field.ConstantValue); + } + + [Test] + public void DefaultOfEnum() + { + ITypeDefinition type = GetTypeDefinition(typeof(ConstantFieldTest)); + IField field = type.Fields.Single(f => f.Name == "DefaultOfEnum"); + Assert.IsTrue(field.IsConst); + Assert.AreEqual((short)default(MyEnum), field.ConstantValue); + } + + [Test] + public void ExplicitImplementation() + { + var type = GetTypeDefinition(typeof(ExplicitImplementationTests)); + var itype = GetTypeDefinition(typeof(IExplicitImplementationTests)); + + var methods = type.GetMethods(m => m.Name == "M").ToList(); + var imethod = itype.GetMethods(m => m.Name == "M").Single(); + Assert.That(methods.Select(m => m.ImplementedInterfaceMembers.Count).ToList(), Is.EquivalentTo(new[] { 0, 1 })); + Assert.AreEqual(methods.SelectMany(m => m.ImplementedInterfaceMembers).Single(), imethod); + + var properties = type.GetProperties(p => p.Name == "P").ToList(); + var iproperty = itype.GetProperties(m => m.Name == "P").Single(); + Assert.That(properties.Select(p => p.ImplementedInterfaceMembers.Count).ToList(), Is.EquivalentTo(new[] { 0, 1 })); + Assert.AreEqual(properties.SelectMany(p => p.ImplementedInterfaceMembers).Single(), iproperty); + Assert.That(properties.Select(p => p.Getter.ImplementedInterfaceMembers.Count).ToList(), Is.EquivalentTo(new[] { 0, 1 })); + Assert.AreEqual(properties.SelectMany(p => p.Getter.ImplementedInterfaceMembers).Single(), iproperty.Getter); + Assert.That(properties.Select(p => p.Setter.ImplementedInterfaceMembers.Count).ToList(), Is.EquivalentTo(new[] { 0, 1 })); + Assert.AreEqual(properties.SelectMany(p => p.Setter.ImplementedInterfaceMembers).Single(), iproperty.Setter); + + var indexers = type.GetProperties(p => p.Name == "Item").ToList(); + var iindexer = itype.GetProperties(m => m.Name == "Item").Single(); + Assert.That(indexers.Select(p => p.ImplementedInterfaceMembers.Count).ToList(), Is.EquivalentTo(new[] { 0, 1 })); + Assert.AreEqual(indexers.SelectMany(p => p.ImplementedInterfaceMembers).Single(), iindexer); + Assert.That(indexers.Select(p => p.Getter.ImplementedInterfaceMembers.Count).ToList(), Is.EquivalentTo(new[] { 0, 1 })); + Assert.AreEqual(indexers.SelectMany(p => p.Getter.ImplementedInterfaceMembers).Single(), iindexer.Getter); + Assert.That(indexers.Select(p => p.Setter.ImplementedInterfaceMembers.Count).ToList(), Is.EquivalentTo(new[] { 0, 1 })); + Assert.AreEqual(indexers.SelectMany(p => p.Setter.ImplementedInterfaceMembers).Single(), iindexer.Setter); + + var events = type.GetEvents(e => e.Name == "E").ToList(); + var ievent = itype.GetEvents(m => m.Name == "E").Single(); + Assert.That(events.Select(e => e.ImplementedInterfaceMembers.Count).ToList(), Is.EquivalentTo(new[] { 0, 1 })); + Assert.AreEqual(events.SelectMany(e => e.ImplementedInterfaceMembers).Single(), ievent); + Assert.That(events.Select(e => e.AddAccessor.ImplementedInterfaceMembers.Count).ToList(), Is.EquivalentTo(new[] { 0, 1 })); + Assert.AreEqual(events.SelectMany(e => e.AddAccessor.ImplementedInterfaceMembers).Single(), ievent.AddAccessor); + Assert.That(events.Select(e => e.RemoveAccessor.ImplementedInterfaceMembers.Count).ToList(), Is.EquivalentTo(new[] { 0, 1 })); + Assert.AreEqual(events.SelectMany(e => e.RemoveAccessor.ImplementedInterfaceMembers).Single(), ievent.RemoveAccessor); + } + + + [Test] + public void MarshalTests() + { + ITypeDefinition c = compilation.FindType(typeof(IMarshalAsTests)).GetDefinition(); + Assert.AreEqual(1, c.GetMethods(m => m.Name == "GetCollectionByQuery2").Count()); + } + + + [Test] + public void AttributesUsingNestedMembers() + { + var type = GetTypeDefinition(typeof(ClassWithAttributesUsingNestedMembers)); + var inner = type.GetNestedTypes().Single(t => t.Name == "Inner"); + var myAttribute = type.GetNestedTypes().Single(t => t.Name == "MyAttribute"); + var typeTypeTestAttr = type.Attributes.Single(a => a.AttributeType.Name == "TypeTestAttribute"); + Assert.AreEqual(42, typeTypeTestAttr.PositionalArguments[0].ConstantValue); + Assert.IsInstanceOf(typeTypeTestAttr.PositionalArguments[1]); + Assert.AreEqual(inner, ((TypeOfResolveResult)typeTypeTestAttr.PositionalArguments[1]).ReferencedType); + var typeMyAttr = type.Attributes.Single(a => a.AttributeType.Name == "MyAttribute"); + Assert.AreEqual(myAttribute, typeMyAttr.AttributeType); + + var prop = type.GetProperties().Single(p => p.Name == "P"); + var propTypeTestAttr = prop.Attributes.Single(a => a.AttributeType.Name == "TypeTestAttribute"); + Assert.AreEqual(42, propTypeTestAttr.PositionalArguments[0].ConstantValue); + Assert.IsInstanceOf(propTypeTestAttr.PositionalArguments[1]); + Assert.AreEqual(inner, ((TypeOfResolveResult)propTypeTestAttr.PositionalArguments[1]).ReferencedType); + var propMyAttr = prop.Attributes.Single(a => a.AttributeType.Name == "MyAttribute"); + Assert.AreEqual(myAttribute, propMyAttr.AttributeType); + + var attributedInner = (ITypeDefinition)type.GetNestedTypes().Single(t => t.Name == "AttributedInner"); + var innerTypeTestAttr = attributedInner.Attributes.Single(a => a.AttributeType.Name == "TypeTestAttribute"); + Assert.AreEqual(42, innerTypeTestAttr.PositionalArguments[0].ConstantValue); + Assert.IsInstanceOf(innerTypeTestAttr.PositionalArguments[1]); + Assert.AreEqual(inner, ((TypeOfResolveResult)innerTypeTestAttr.PositionalArguments[1]).ReferencedType); + var innerMyAttr = attributedInner.Attributes.Single(a => a.AttributeType.Name == "MyAttribute"); + Assert.AreEqual(myAttribute, innerMyAttr.AttributeType); + + var attributedInner2 = (ITypeDefinition)type.GetNestedTypes().Single(t => t.Name == "AttributedInner2"); + var inner2 = attributedInner2.GetNestedTypes().Single(t => t.Name == "Inner"); + var myAttribute2 = attributedInner2.GetNestedTypes().Single(t => t.Name == "MyAttribute"); + var inner2TypeTestAttr = attributedInner2.Attributes.Single(a => a.AttributeType.Name == "TypeTestAttribute"); + Assert.AreEqual(43, inner2TypeTestAttr.PositionalArguments[0].ConstantValue); + Assert.IsInstanceOf(inner2TypeTestAttr.PositionalArguments[1]); + Assert.AreEqual(inner2, ((TypeOfResolveResult)inner2TypeTestAttr.PositionalArguments[1]).ReferencedType); + var inner2MyAttr = attributedInner2.Attributes.Single(a => a.AttributeType.Name == "MyAttribute"); + Assert.AreEqual(myAttribute2, inner2MyAttr.AttributeType); + } + + [Test] + public void ClassWithAttributeOnTypeParameter() + { + var tp = GetTypeDefinition(typeof(ClassWithAttributeOnTypeParameter<>)).TypeParameters.Single(); + var attr = tp.Attributes.Single(); + Assert.AreEqual("DoubleAttribute", attr.AttributeType.Name); + } + + [Test] + public void InheritanceTest() + { + ITypeDefinition c = compilation.FindType(typeof(SystemException)).GetDefinition(); + ITypeDefinition c2 = compilation.FindType(typeof(Exception)).GetDefinition(); + Assert.IsNotNull(c, "c is null"); + Assert.IsNotNull(c2, "c2 is null"); + //Assert.AreEqual(3, c.BaseTypes.Count); // Inherited interfaces are not reported by Cecil + // which matches the behaviour of our C#/VB parsers + Assert.AreEqual("System.Exception", c.DirectBaseTypes.First().FullName); + Assert.AreSame(c2, c.DirectBaseTypes.First()); + + string[] superTypes = c.GetAllBaseTypes().Select(t => t.ReflectionName).ToArray(); + Assert.AreEqual(new string[] { + "System.Object", + "System.Runtime.Serialization.ISerializable", "System.Runtime.InteropServices._Exception", + "System.Exception", "System.SystemException" + }, superTypes); + } + + [Test] + public void GenericPropertyTest() + { + ITypeDefinition c = compilation.FindType(typeof(Comparer<>)).GetDefinition(); + IProperty def = c.Properties.Single(p => p.Name == "Default"); + ParameterizedType pt = (ParameterizedType)def.ReturnType; + Assert.AreEqual("System.Collections.Generic.Comparer", pt.FullName); + Assert.AreEqual(c.TypeParameters[0], pt.TypeArguments[0]); + } + + [Test] + public void PointerTypeTest() + { + ITypeDefinition c = compilation.FindType(typeof(IntPtr)).GetDefinition(); + IMethod toPointer = c.Methods.Single(p => p.Name == "ToPointer"); + Assert.AreEqual("System.Void*", toPointer.ReturnType.ReflectionName); + Assert.IsTrue(toPointer.ReturnType is PointerType); + Assert.AreEqual("System.Void", ((PointerType)toPointer.ReturnType).ElementType.FullName); + } + + [Test] + public void DateTimeDefaultConstructor() + { + ITypeDefinition c = compilation.FindType(typeof(DateTime)).GetDefinition(); + Assert.AreEqual(1, c.Methods.Count(m => m.IsConstructor && m.Parameters.Count == 0)); + Assert.AreEqual(1, c.GetConstructors().Count(m => m.Parameters.Count == 0)); + } + + [Test] + public void NoEncodingInfoDefaultConstructor() + { + ITypeDefinition c = compilation.FindType(typeof(EncodingInfo)).GetDefinition(); + // EncodingInfo only has an internal constructor + Assert.IsFalse(c.Methods.Any(m => m.IsConstructor)); + // and no implicit ctor should be added: + Assert.AreEqual(0, c.GetConstructors().Count()); + } + + [Test] + public void StaticModifierTest() + { + ITypeDefinition c = compilation.FindType(typeof(Environment)).GetDefinition(); + Assert.IsNotNull(c, "System.Environment not found"); + Assert.IsTrue(c.IsAbstract, "class should be abstract"); + Assert.IsTrue(c.IsSealed, "class should be sealed"); + Assert.IsTrue(c.IsStatic, "class should be static"); + } + + [Test] + public void InnerClassReferenceTest() + { + ITypeDefinition c = compilation.FindType(typeof(Environment)).GetDefinition(); + Assert.IsNotNull(c, "System.Environment not found"); + IType rt = c.Methods.First(m => m.Name == "GetFolderPath").Parameters[0].Type; + Assert.AreSame(c.NestedTypes.Single(ic => ic.Name == "SpecialFolder"), rt); + } + + [Test] + public void NestedTypesTest() + { + ITypeDefinition c = compilation.FindType(typeof(Environment.SpecialFolder)).GetDefinition(); + Assert.IsNotNull(c, "c is null"); + Assert.AreEqual("System.Environment.SpecialFolder", c.FullName); + Assert.AreEqual("System.Environment+SpecialFolder", c.ReflectionName); + } + + [Test] + public void VoidHasNoMembers() + { + ITypeDefinition c = compilation.FindType(typeof(void)).GetDefinition(); + Assert.IsNotNull(c, "System.Void not found"); + Assert.AreEqual(0, c.GetMethods().Count()); + Assert.AreEqual(0, c.GetProperties().Count()); + Assert.AreEqual(0, c.GetEvents().Count()); + Assert.AreEqual(0, c.GetFields().Count()); + } + + [Test] + public void Void_SerializableAttribute() + { + ITypeDefinition c = compilation.FindType(typeof(void)).GetDefinition(); + var attr = c.Attributes.Single(a => a.AttributeType.FullName == "System.SerializableAttribute"); + Assert.AreEqual(0, attr.Constructor.Parameters.Count); + Assert.AreEqual(0, attr.PositionalArguments.Count); + Assert.AreEqual(0, attr.NamedArguments.Count); + } + + [Test] + public void Void_StructLayoutAttribute() + { + ITypeDefinition c = compilation.FindType(typeof(void)).GetDefinition(); + var attr = c.Attributes.Single(a => a.AttributeType.FullName == "System.Runtime.InteropServices.StructLayoutAttribute"); + Assert.AreEqual(1, attr.Constructor.Parameters.Count); + Assert.AreEqual(1, attr.PositionalArguments.Count); + Assert.AreEqual(0, attr.PositionalArguments[0].ConstantValue); + Assert.AreEqual(1, attr.NamedArguments.Count); + Assert.AreEqual("System.Runtime.InteropServices.StructLayoutAttribute.Size", attr.NamedArguments[0].Key.FullName); + Assert.AreEqual(1, attr.NamedArguments[0].Value.ConstantValue); + } + + [Test] + public void Void_ComVisibleAttribute() + { + ITypeDefinition c = compilation.FindType(typeof(void)).GetDefinition(); + var attr = c.Attributes.Single(a => a.AttributeType.FullName == "System.Runtime.InteropServices.ComVisibleAttribute"); + Assert.AreEqual(1, attr.Constructor.Parameters.Count); + Assert.AreEqual(1, attr.PositionalArguments.Count); + Assert.AreEqual(true, attr.PositionalArguments[0].ConstantValue); + Assert.AreEqual(0, attr.NamedArguments.Count); + } + + [Test] + public void NestedClassInGenericClassTest() + { + ITypeDefinition dictionary = compilation.FindType(typeof(Dictionary<,>)).GetDefinition(); + Assert.IsNotNull(dictionary); + ITypeDefinition valueCollection = compilation.FindType(typeof(Dictionary<,>.ValueCollection)).GetDefinition(); + Assert.IsNotNull(valueCollection); + var dictionaryRT = new ParameterizedType(dictionary, new[] { compilation.FindType(typeof(string)).GetDefinition(), compilation.FindType(typeof(int)).GetDefinition() }); + IProperty valueProperty = dictionaryRT.GetProperties(p => p.Name == "Values").Single(); + IType parameterizedValueCollection = valueProperty.ReturnType; + Assert.AreEqual("System.Collections.Generic.Dictionary`2+ValueCollection[[System.String],[System.Int32]]", parameterizedValueCollection.ReflectionName); + Assert.AreSame(valueCollection, parameterizedValueCollection.GetDefinition()); + } + + [Test] + public void ValueCollectionCountModifiers() + { + ITypeDefinition valueCollection = compilation.FindType(typeof(Dictionary<,>.ValueCollection)).GetDefinition(); + Assert.AreEqual(Accessibility.Public, valueCollection.Accessibility); + Assert.IsTrue(valueCollection.IsSealed); + Assert.IsFalse(valueCollection.IsAbstract); + Assert.IsFalse(valueCollection.IsStatic); + + IProperty count = valueCollection.Properties.Single(p => p.Name == "Count"); + Assert.AreEqual(Accessibility.Public, count.Accessibility); + // It's sealed on the IL level; but in C# it's just a normal non-virtual method that happens to implement an interface + Assert.IsFalse(count.IsSealed); + Assert.IsFalse(count.IsVirtual); + Assert.IsFalse(count.IsAbstract); + } + + [Test] + public void MathAcosModifiers() + { + ITypeDefinition math = compilation.FindType(typeof(Math)).GetDefinition(); + Assert.AreEqual(Accessibility.Public, math.Accessibility); + Assert.IsTrue(math.IsSealed); + Assert.IsTrue(math.IsAbstract); + Assert.IsTrue(math.IsStatic); + + IMethod acos = math.Methods.Single(p => p.Name == "Acos"); + Assert.AreEqual(Accessibility.Public, acos.Accessibility); + Assert.IsTrue(acos.IsStatic); + Assert.IsFalse(acos.IsAbstract); + Assert.IsFalse(acos.IsSealed); + Assert.IsFalse(acos.IsVirtual); + Assert.IsFalse(acos.IsOverride); + } + + [Test] + public void EncodingModifiers() + { + ITypeDefinition encoding = compilation.FindType(typeof(Encoding)).GetDefinition(); + Assert.AreEqual(Accessibility.Public, encoding.Accessibility); + Assert.IsFalse(encoding.IsSealed); + Assert.IsTrue(encoding.IsAbstract); + + IMethod getDecoder = encoding.Methods.Single(p => p.Name == "GetDecoder"); + Assert.AreEqual(Accessibility.Public, getDecoder.Accessibility); + Assert.IsFalse(getDecoder.IsStatic); + Assert.IsFalse(getDecoder.IsAbstract); + Assert.IsFalse(getDecoder.IsSealed); + Assert.IsTrue(getDecoder.IsVirtual); + Assert.IsFalse(getDecoder.IsOverride); + + IMethod getMaxByteCount = encoding.Methods.Single(p => p.Name == "GetMaxByteCount"); + Assert.AreEqual(Accessibility.Public, getMaxByteCount.Accessibility); + Assert.IsFalse(getMaxByteCount.IsStatic); + Assert.IsTrue(getMaxByteCount.IsAbstract); + Assert.IsFalse(getMaxByteCount.IsSealed); + Assert.IsFalse(getMaxByteCount.IsVirtual); + Assert.IsFalse(getMaxByteCount.IsOverride); + + IProperty encoderFallback = encoding.Properties.Single(p => p.Name == "EncoderFallback"); + Assert.AreEqual(Accessibility.Public, encoderFallback.Accessibility); + Assert.IsFalse(encoderFallback.IsStatic); + Assert.IsFalse(encoderFallback.IsAbstract); + Assert.IsFalse(encoderFallback.IsSealed); + Assert.IsFalse(encoderFallback.IsVirtual); + Assert.IsFalse(encoderFallback.IsOverride); + } + + [Test] + public void UnicodeEncodingModifiers() + { + ITypeDefinition encoding = compilation.FindType(typeof(UnicodeEncoding)).GetDefinition(); + Assert.AreEqual(Accessibility.Public, encoding.Accessibility); + Assert.IsFalse(encoding.IsSealed); + Assert.IsFalse(encoding.IsAbstract); + + IMethod getDecoder = encoding.Methods.Single(p => p.Name == "GetDecoder"); + Assert.AreEqual(Accessibility.Public, getDecoder.Accessibility); + Assert.IsFalse(getDecoder.IsStatic); + Assert.IsFalse(getDecoder.IsAbstract); + Assert.IsFalse(getDecoder.IsSealed); + Assert.IsFalse(getDecoder.IsVirtual); + Assert.IsTrue(getDecoder.IsOverride); + } + + [Test] + public void UTF32EncodingModifiers() + { + ITypeDefinition encoding = compilation.FindType(typeof(UTF32Encoding)).GetDefinition(); + Assert.AreEqual(Accessibility.Public, encoding.Accessibility); + Assert.IsTrue(encoding.IsSealed); + Assert.IsFalse(encoding.IsAbstract); + + IMethod getDecoder = encoding.Methods.Single(p => p.Name == "GetDecoder"); + Assert.AreEqual(Accessibility.Public, getDecoder.Accessibility); + Assert.IsFalse(getDecoder.IsStatic); + Assert.IsFalse(getDecoder.IsAbstract); + Assert.IsFalse(getDecoder.IsSealed); + Assert.IsFalse(getDecoder.IsVirtual); + Assert.IsTrue(getDecoder.IsOverride); + } + + [Test] + public void FindRedirectedType() + { + var compilationWithSystemCore = new SimpleCompilation(SystemCore, Mscorlib); + + var typeRef = ReflectionHelper.ParseReflectionName("System.Func`2, System.Core"); + ITypeDefinition c = typeRef.Resolve(compilationWithSystemCore.TypeResolveContext).GetDefinition(); + Assert.IsNotNull(c, "System.Func<,> not found"); + Assert.AreEqual("mscorlib", c.ParentAssembly.AssemblyName); + } + + public void DelegateIsClass() + { + var @delegate = compilation.FindType(KnownTypeCode.Delegate).GetDefinition(); + Assert.AreEqual(TypeKind.Class, @delegate); + Assert.IsFalse(@delegate.IsSealed); + } + + public void MulticastDelegateIsClass() + { + var multicastDelegate = compilation.FindType(KnownTypeCode.MulticastDelegate).GetDefinition(); + Assert.AreEqual(TypeKind.Class, multicastDelegate); + Assert.IsFalse(multicastDelegate.IsSealed); + } + } +} diff --git a/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs new file mode 100644 index 000000000..abe89eed3 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs @@ -0,0 +1,675 @@ +// Copyright (c) 2010-2018 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +[assembly: ICSharpCode.Decompiler.Tests.TypeSystem.TypeTestAttribute( + 42, typeof(System.Action<>), typeof(IDictionary>))] + +[assembly: TypeForwardedTo(typeof(Func<,>))] + +namespace ICSharpCode.Decompiler.Tests.TypeSystem +{ + public delegate S GenericDelegate(T input) where T : S where S : class; + + public class SimplePublicClass + { + public void Method() { } + } + + public class TypeTestAttribute : Attribute + { + public TypeTestAttribute(int a1, Type a2, Type a3) { } + } + + [Params(1, StringComparison.CurrentCulture, null, 4.0, "Test")] + public class ParamsAttribute : Attribute + { + public ParamsAttribute(params object[] x) { } + + [Params(Property = new string[] { "a", "b" })] + public string[] Property { + [return: Params("Attribute on return type of getter")] + get { return null; } + set { } + } + } + + [Double(1)] + public class DoubleAttribute : Attribute + { + public DoubleAttribute(double val) { } + } + + public unsafe class DynamicTest + { + public dynamic SimpleProperty { get; set; } + + public List DynamicGenerics1(Action param) { return null; } + public void DynamicGenerics2(Action param) { } + public void DynamicGenerics3(Action param) { } + public void DynamicGenerics4(Action param) { } + public void DynamicGenerics5(Action param) { } + public void DynamicGenerics6(ref Action param) { } + public void DynamicGenerics7(Action param) { } + } + + public class GenericClass where A : B + { + public void TestMethod(string param) where V : K where K : IComparable { } + public void GetIndex(T element) where T : IEquatable { } + + public NestedEnum EnumField; + + public A Property { get; set; } + + public enum NestedEnum + { + EnumMember + } + } + + public class PropertyTest + { + public int PropertyWithProtectedSetter { get; protected set; } + + public object PropertyWithPrivateSetter { get; private set; } + + public object PropertyWithoutSetter { get { return null; } } + + public object PropertyWithPrivateGetter { private get; set; } + + public string this[int index] { get { return "Test"; } set { } } + } + + public enum MyEnum : short + { + First, + Second, + Flag1 = 0x10, + Flag2 = 0x20, + CombinedFlags = Flag1 | Flag2 + } + + public class Base + { + public class Nested { } + + public virtual void GenericMethodWithConstraints(T a) where X : IComparer, new() { } + } + public class Derived : Base + { + public override void GenericMethodWithConstraints(B a) { } + } + + public struct MyStructWithCtor + { + public MyStructWithCtor(int a) { } + } + + public class MyClassWithCtor + { + private MyClassWithCtor(int a) { } + } + + [Serializable] + public class NonCustomAttributes + { + [NonSerialized] + public readonly int NonSerializedField; + + [DllImport("unmanaged.dll", CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DllMethod([In, Out] ref int p); + } + + [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 8)] + public struct ExplicitFieldLayoutStruct + { + [FieldOffset(0)] + public int Field0; + + [FieldOffset(100)] + public int Field100; + } + + public class ParameterTests + { + public void MethodWithOutParameter(out int x) { x = 0; } + public void MethodWithParamsArray(params object[] x) { } + public void MethodWithOptionalParameter(int x = 4) { } + public void MethodWithExplicitOptionalParameter([Optional] int x) { } + public void MethodWithEnumOptionalParameter(StringComparison x = StringComparison.OrdinalIgnoreCase) { } + public void MethodWithOptionalNullableParameter(int? x = null) { } + public void MethodWithOptionalLongParameter(long x = 1) { } + public void MethodWithOptionalNullableLongParameter(long? x = 1) { } + public void VarArgsMethod(__arglist) { } + } + + public class VarArgsCtor + { + public VarArgsCtor(__arglist) { } + } + + [ComImport(), Guid("21B8916C-F28E-11D2-A473-00C04F8EF448"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IAssemblyEnum + { + [PreserveSig()] + int GetNextAssembly(uint dwFlags); + } + + public class OuterGeneric + { + public class Inner + { + public OuterGeneric referenceToOuter; + public Inner(OuterGeneric referenceToOuter) { } + } + + public OuterGeneric.Inner Field1; + public Inner Field2; + public OuterGeneric.Inner>.Inner Field3; + } + + public class ExplicitDisposableImplementation : IDisposable + { + void IDisposable.Dispose() { } + } + + public interface IGenericInterface + { + void Test(T a, S b) where S : T; + void Test(T a, ref S b); + } + + public class ExplicitGenericInterfaceImplementation : IGenericInterface + { + void IGenericInterface.Test(string a, T b) { } + void IGenericInterface.Test(string a, ref T b) { } + } + + public interface IGenericInterfaceWithUnifiableMethods + { + void Test(T a); + void Test(S a); + } + + public class ImplementationOfUnifiedMethods : IGenericInterfaceWithUnifiableMethods + { + public void Test(int a) { } + } + + public class ExplicitGenericInterfaceImplementationWithUnifiableMethods : IGenericInterfaceWithUnifiableMethods + { + void IGenericInterfaceWithUnifiableMethods.Test(T a) { } + void IGenericInterfaceWithUnifiableMethods.Test(S a) { } + } + + public partial class PartialClass + { + partial void PartialMethodWithImplementation(int a); + + partial void PartialMethodWithImplementation(System.Int32 a) + { + } + + partial void PartialMethodWithImplementation(string a); + + partial void PartialMethodWithImplementation(System.String a) + { + } + + partial void PartialMethodWithoutImplementation(); + } + + public class ClassWithStaticAndNonStaticMembers + { + public static event System.EventHandler Event1 { add { } remove { } } + public event System.EventHandler Event2 { add { } remove { } } +#pragma warning disable 67 + public static event System.EventHandler Event3; + public event System.EventHandler Event4; + + public static int Prop1 { get { return 0; } set { } } + public int Prop2 { get { return 0; } set { } } + public static int Prop3 { get; set; } + public int Prop4 { get; set; } + } + + public interface IInterfaceWithProperty + { + int Prop { get; set; } + } + + public class ClassWithVirtualProperty + { + public virtual int Prop { get; protected set; } + } + + public class ClassThatOverridesAndSealsVirtualProperty : ClassWithVirtualProperty + { + public sealed override int Prop { get; protected set; } + } + + public class ClassThatOverridesGetterOnly : ClassWithVirtualProperty + { + public override int Prop { get { return 1; } } + } + + public class ClassThatOverridesSetterOnly : ClassThatOverridesGetterOnly + { + public override int Prop { protected set { } } + } + + public class ClassThatImplementsProperty : IInterfaceWithProperty + { + public int Prop { get; set; } + } + + public class ClassThatImplementsPropertyExplicitly : IInterfaceWithProperty + { + int IInterfaceWithProperty.Prop { get; set; } + } + + public interface IInterfaceWithIndexers + { + int this[int x] { get; set; } + int this[string x] { get; set; } + int this[int x, int y] { get; set; } + } + + public interface IGenericInterfaceWithIndexer + { + int this[T x] { get; set; } + } + + public class ClassThatImplementsIndexers : IInterfaceWithIndexers, IGenericInterfaceWithIndexer + { + public int this[int x] { get { return 0; } set { } } + public int this[string x] { get { return 0; } set { } } + public int this[int x, int y] { get { return 0; } set { } } + } + + public class ClassThatImplementsIndexersExplicitly : IInterfaceWithIndexers, IGenericInterfaceWithIndexer + { + int IInterfaceWithIndexers.this[int x] { get { return 0; } set { } } + int IGenericInterfaceWithIndexer.this[int x] { get { return 0; } set { } } + int IInterfaceWithIndexers.this[string x] { get { return 0; } set { } } + int IInterfaceWithIndexers.this[int x, int y] { get { return 0; } set { } } + } + + public interface IHasEvent + { + event EventHandler Event; + } + + public class ClassThatImplementsEvent : IHasEvent + { + public event EventHandler Event; + } + + public class ClassThatImplementsEventWithCustomAccessors : IHasEvent + { + public event EventHandler Event { add { } remove { } } + } + + public class ClassThatImplementsEventExplicitly : IHasEvent + { + event EventHandler IHasEvent.Event { add { } remove { } } + } + + public interface IShadowTestBase + { + void Method(); + int this[int i] { get; set; } + int Prop { get; set; } + event EventHandler Evt; + } + + public interface IShadowTestDerived : IShadowTestBase + { + new void Method(); + new int this[int i] { get; set; } + new int Prop { get; set; } + new event EventHandler Evt; + } + + public static class StaticClass { } + public abstract class AbstractClass { } + + public class IndexerNonDefaultName + { + [IndexerName("Foo")] + public int this[int index] { + get { return 0; } + } + } + + public class ClassWithMethodThatHasNullableDefaultParameter + { + public void Foo(int? bar = 42) { } + } + + public class AccessibilityTest + { + public void Public() { } + internal void Internal() { } + protected internal void ProtectedInternal() { } + internal protected void InternalProtected() { } + protected void Protected() { } + private void Private() { } + void None() { } + } + + public class ConstantFieldTest + { + public const byte Cb = 42; + public const sbyte Csb = 42; + public const char Cc = '\x42'; + public const short Cs = 42; + public const ushort Cus = 42; + public const int Ci = 42; + public const uint Cui = 42; + public const long Cl = 42; + public const ulong Cul = 42; + public const double Cd = 42; + public const float Cf = 42; + public const decimal Cm = 42; + public const string S = "hello, world"; + public const string NullString = null; + + public const MyEnum EnumFromThisAssembly = MyEnum.Second; + public const StringComparison EnumFromAnotherAssembly = StringComparison.OrdinalIgnoreCase; + public const MyEnum DefaultOfEnum = default(MyEnum); + + public const int SOsb = sizeof(sbyte); + public const int SOb = sizeof(byte); + public const int SOs = sizeof(short); + public const int SOus = sizeof(ushort); + public const int SOi = sizeof(int); + public const int SOui = sizeof(uint); + public const int SOl = sizeof(long); + public const int SOul = sizeof(ulong); + public const int SOc = sizeof(char); + public const int SOf = sizeof(float); + public const int SOd = sizeof(double); + public const int SObl = sizeof(bool); + public const int SOe = sizeof(MyEnum); + + + public const byte CNewb = new byte(); + public const sbyte CNewsb = new sbyte(); + public const char CNewc = new char(); + public const short CNews = new short(); + public const ushort CNewus = new ushort(); + public const int CNewi = new int(); + public const uint CNewui = new uint(); + public const long CNewl = new long(); + public const ulong CNewul = new ulong(); + public const double CNewd = new double(); + public const float CNewf = new float(); + public const decimal CNewm = new decimal(); + } + + public interface IExplicitImplementationTests + { + void M(int a); + int P { get; set; } + event Action E; + int this[int x] { get; set; } + } + + public class ExplicitImplementationTests : IExplicitImplementationTests + { + public void M(int a) { } + public int P { get; set; } + public event Action E; + public int this[int x] { get { return 0; } set { } } + + void IExplicitImplementationTests.M(int a) { } + int IExplicitImplementationTests.P { get; set; } + event Action IExplicitImplementationTests.E { add { } remove { } } + int IExplicitImplementationTests.this[int x] { get { return 0; } set { } } + } + + [TypeTest(C, typeof(Inner), typeof(int)), My] + public class ClassWithAttributesUsingNestedMembers + { + sealed class MyAttribute : Attribute { } + + const int C = 42; + class Inner + { + } + + [TypeTest(C, typeof(Inner), typeof(int)), My] + public int P { get; set; } + + [TypeTest(C, typeof(Inner), typeof(int)), My] + class AttributedInner + { + } + + [TypeTest(C, typeof(Inner), typeof(int)), My] + class AttributedInner2 + { + sealed class MyAttribute : Attribute { } + + const int C = 43; + class Inner { } + } + } + + public class ClassWithAttributeOnTypeParameter<[Double(2)] T> { } + + [Guid("790C6E0B-9194-4cc9-9426-A48A63185696"), InterfaceType(ComInterfaceType.InterfaceIsDual)] + [ComImport] + public interface IMarshalAsTests + { + [DispId(48)] + void AliasComponent([MarshalAs(UnmanagedType.BStr)] [In] string bstrSrcApplicationIDOrName, [MarshalAs(UnmanagedType.BStr)] [In] string bstrCLSIDOrProgID, [MarshalAs(UnmanagedType.BStr)] [In] string bstrDestApplicationIDOrName, [MarshalAs(UnmanagedType.BStr)] [In] string bstrNewProgId, [MarshalAs(UnmanagedType.BStr)] [In] string bstrNewClsid); + + [DispId(33)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool AreApplicationInstancesPaused([MarshalAs(UnmanagedType.LPStruct)] [In] object pVarApplicationInstanceID); + + [DispId(19)] + void BackupREGDB([MarshalAs(UnmanagedType.BStr)] [In] string bstrBackupFilePath); + + [DispId(2)] + [return: MarshalAs(UnmanagedType.Interface)] + object Connect([MarshalAs(UnmanagedType.BStr)] [In] string connectStr); + + [DispId(45)] + void CopyApplications([MarshalAs(UnmanagedType.BStr)] [In] string bstrSourcePartitionIDOrName, [MarshalAs(UnmanagedType.LPStruct)] [In] object pVarApplicationID, [MarshalAs(UnmanagedType.BStr)] [In] string bstrDestinationPartitionIDOrName); + + [DispId(46)] + void CopyComponents([MarshalAs(UnmanagedType.BStr)] [In] string bstrSourceApplicationIDOrName, [MarshalAs(UnmanagedType.LPStruct)] [In] object pVarCLSIDOrProgID, [MarshalAs(UnmanagedType.BStr)] [In] string bstrDestinationApplicationIDOrName); + + [DispId(36)] + void CreateServiceForApplication([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationIDOrName, [MarshalAs(UnmanagedType.BStr)] [In] string bstrServiceName, [MarshalAs(UnmanagedType.BStr)] [In] string bstrStartType, [MarshalAs(UnmanagedType.BStr)] [In] string bstrErrorControl, [MarshalAs(UnmanagedType.BStr)] [In] string bstrDependencies, [MarshalAs(UnmanagedType.BStr)] [In] string bstrRunAs, [MarshalAs(UnmanagedType.BStr)] [In] string bstrPassword, [MarshalAs(UnmanagedType.VariantBool)] [In] bool bDesktopOk); + + [DispId(40)] + void CurrentPartition([MarshalAs(UnmanagedType.BStr)] [In] string bstrPartitionIDOrName); + + [DispId(41)] + [return: MarshalAs(UnmanagedType.BStr)] + string CurrentPartitionID(); + + [DispId(42)] + [return: MarshalAs(UnmanagedType.BStr)] + string CurrentPartitionName(); + + [DispId(37)] + void DeleteServiceForApplication([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationIDOrName); + + [DispId(34)] + [return: MarshalAs(UnmanagedType.BStr)] + string DumpApplicationInstance([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationInstanceID, [MarshalAs(UnmanagedType.BStr)] [In] string bstrDirectory, [MarshalAs(UnmanagedType.I4)] [In] int lMaxImages); + + [DispId(9)] + void ExportApplication([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplIdOrName, [MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationFile, [In] int lOptions); + + [DispId(54)] + void ExportPartition([MarshalAs(UnmanagedType.BStr)] [In] string bstrPartitionIDOrName, [MarshalAs(UnmanagedType.BStr)] [In] string bstrPartitionFileName, [MarshalAs(UnmanagedType.I4)] [In] int lOptions); + + [DispId(44)] + void FlushPartitionCache(); + + [DispId(28)] + [return: MarshalAs(UnmanagedType.BStr)] + string GetApplicationInstanceIDFromProcessID([MarshalAs(UnmanagedType.I4)] [In] int lProcessID); + + [DispId(1)] + [return: MarshalAs(UnmanagedType.Interface)] + object GetCollection([MarshalAs(UnmanagedType.BStr)] [In] string bstrCollName); + + [DispId(5)] + [return: MarshalAs(UnmanagedType.Interface)] + object GetCollectionByQuery([MarshalAs(UnmanagedType.BStr)] [In] string collName, [MarshalAs(UnmanagedType.SafeArray)] [In] ref object[] aQuery); + + [DispId(27)] + [return: MarshalAs(UnmanagedType.Interface)] + object GetCollectionByQuery2([MarshalAs(UnmanagedType.BStr)] [In] string bstrCollectionName, [MarshalAs(UnmanagedType.LPStruct)] [In] object pVarQueryStrings); + + [DispId(57)] + [return: MarshalAs(UnmanagedType.I4)] + int GetComponentVersionCount([MarshalAs(UnmanagedType.BStr)] [In] string bstrCLSIDOrProgID); + + [DispId(26)] + void GetEventClassesForIID([In] string bstrIID, [MarshalAs(UnmanagedType.SafeArray)] [In] [Out] ref object[] varCLSIDS, [MarshalAs(UnmanagedType.SafeArray)] [In] [Out] ref object[] varProgIDs, [MarshalAs(UnmanagedType.SafeArray)] [In] [Out] ref object[] varDescriptions); + + [DispId(17)] + void GetMultipleComponentsInfo([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplIdOrName, [In] object varFileNames, [MarshalAs(UnmanagedType.SafeArray)] out object[] varCLSIDS, [MarshalAs(UnmanagedType.SafeArray)] out object[] varClassNames, [MarshalAs(UnmanagedType.SafeArray)] out object[] varFileFlags, [MarshalAs(UnmanagedType.SafeArray)] out object[] varComponentFlags); + + [DispId(38)] + [return: MarshalAs(UnmanagedType.BStr)] + string GetPartitionID([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationIDOrName); + + [DispId(39)] + [return: MarshalAs(UnmanagedType.BStr)] + string GetPartitionName([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationIDOrName); + + [DispId(43)] + [return: MarshalAs(UnmanagedType.BStr)] + string GlobalPartitionID(); + + [DispId(6)] + void ImportComponent([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplIdOrName, [MarshalAs(UnmanagedType.BStr)] [In] string bstrCLSIDOrProgId); + + [DispId(52)] + void ImportComponents([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationIDOrName, [MarshalAs(UnmanagedType.LPStruct)] [In] object pVarCLSIDOrProgID, [MarshalAs(UnmanagedType.LPStruct)] [In] object pVarComponentType); + + [DispId(50)] + void ImportUnconfiguredComponents([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationIDOrName, [MarshalAs(UnmanagedType.LPStruct)] [In] object pVarCLSIDOrProgID, [MarshalAs(UnmanagedType.LPStruct)] [In] object pVarComponentType); + + [DispId(10)] + void InstallApplication([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationFile, [MarshalAs(UnmanagedType.BStr)] [In] string bstrDestinationDirectory, [In] int lOptions, [MarshalAs(UnmanagedType.BStr)] [In] string bstrUserId, [MarshalAs(UnmanagedType.BStr)] [In] string bstrPassword, [MarshalAs(UnmanagedType.BStr)] [In] string bstrRSN); + + [DispId(7)] + void InstallComponent([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplIdOrName, [MarshalAs(UnmanagedType.BStr)] [In] string bstrDLL, [MarshalAs(UnmanagedType.BStr)] [In] string bstrTLB, [MarshalAs(UnmanagedType.BStr)] [In] string bstrPSDLL); + + [DispId(25)] + void InstallEventClass([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplIdOrName, [MarshalAs(UnmanagedType.BStr)] [In] string bstrDLL, [MarshalAs(UnmanagedType.BStr)] [In] string bstrTLB, [MarshalAs(UnmanagedType.BStr)] [In] string bstrPSDLL); + + [DispId(16)] + void InstallMultipleComponents([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplIdOrName, [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] [In] ref object[] fileNames, [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] [In] ref object[] CLSIDS); + + [DispId(24)] + void InstallMultipleEventClasses([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplIdOrName, [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] [In] ref object[] fileNames, [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] [In] ref object[] CLSIDS); + + [DispId(55)] + void InstallPartition([MarshalAs(UnmanagedType.BStr)] [In] string bstrFileName, [MarshalAs(UnmanagedType.BStr)] [In] string bstrDestDirectory, [MarshalAs(UnmanagedType.I4)] [In] int lOptions, [MarshalAs(UnmanagedType.BStr)] [In] string bstrUserID, [MarshalAs(UnmanagedType.BStr)] [In] string bstrPassword, [MarshalAs(UnmanagedType.BStr)] [In] string bstrRSN); + + [DispId(53)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool Is64BitCatalogServer(); + + [DispId(35)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool IsApplicationInstanceDumpSupported(); + + [DispId(49)] + [return: MarshalAs(UnmanagedType.Interface)] + object IsSafeToDelete([MarshalAs(UnmanagedType.BStr)] [In] string bstrDllName); + + [DispId(3)] + int MajorVersion(); + + [DispId(4)] + int MinorVersion(); + + [DispId(47)] + void MoveComponents([MarshalAs(UnmanagedType.BStr)] [In] string bstrSourceApplicationIDOrName, [MarshalAs(UnmanagedType.LPStruct)] [In] object pVarCLSIDOrProgID, [MarshalAs(UnmanagedType.BStr)] [In] string bstrDestinationApplicationIDOrName); + + [DispId(30)] + void PauseApplicationInstances([MarshalAs(UnmanagedType.LPStruct)] [In] object pVarApplicationInstanceID); + + [DispId(51)] + void PromoteUnconfiguredComponents([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationIDOrName, [MarshalAs(UnmanagedType.LPStruct)] [In] object pVarCLSIDOrProgID, [MarshalAs(UnmanagedType.LPStruct)] [In] object pVarComponentType); + + [DispId(21)] + void QueryApplicationFile([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationFile, [MarshalAs(UnmanagedType.BStr)] out string bstrApplicationName, [MarshalAs(UnmanagedType.BStr)] out string bstrApplicationDescription, [MarshalAs(UnmanagedType.VariantBool)] out bool bHasUsers, [MarshalAs(UnmanagedType.VariantBool)] out bool bIsProxy, [MarshalAs(UnmanagedType.SafeArray)] out object[] varFileNames); + + [DispId(56)] + [return: MarshalAs(UnmanagedType.IDispatch)] + object QueryApplicationFile2([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplicationFile); + + [DispId(32)] + void RecycleApplicationInstances([MarshalAs(UnmanagedType.LPStruct)] [In] object pVarApplicationInstanceID, [MarshalAs(UnmanagedType.I4)] [In] int lReasonCode); + + [DispId(18)] + void RefreshComponents(); + + [DispId(12)] + void RefreshRouter(); + + [DispId(14)] + void Reserved1(); + + [DispId(15)] + void Reserved2(); + + [DispId(20)] + void RestoreREGDB([MarshalAs(UnmanagedType.BStr)] [In] string bstrBackupFilePath); + + [DispId(31)] + void ResumeApplicationInstances([MarshalAs(UnmanagedType.LPStruct)] [In] object pVarApplicationInstanceID); + + [DispId(23)] + int ServiceCheck([In] int lService); + + [DispId(8)] + void ShutdownApplication([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplIdOrName); + + [DispId(29)] + void ShutdownApplicationInstances([MarshalAs(UnmanagedType.LPStruct)] [In] object pVarApplicationInstanceID); + + [DispId(22)] + void StartApplication([MarshalAs(UnmanagedType.BStr)] [In] string bstrApplIdOrName); + + [DispId(13)] + void StartRouter(); + + [DispId(11)] + void StopRouter(); + } +}