diff --git a/ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs b/ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs index e403b3b26..898852b39 100644 --- a/ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs +++ b/ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs @@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.Tests.Output ambience = new CSharpAmbience(); compilation = new SimpleCompilation(TypeSystemLoaderTests.TestAssembly, - TypeSystemLoaderTests.Mscorlib.WithOptions(TypeSystemOptions.Default | TypeSystemOptions.OnlyPublicAPI)); + TypeSystemLoaderTests.Mscorlib.WithOptions(TypeSystemOptions.Default)); } ITypeDefinition GetDefinition(Type type) @@ -266,31 +266,47 @@ namespace ICSharpCode.Decompiler.Tests.Output #endregion #region Property tests - [Test] - public void AutomaticProperty() + [TestCase(StandardConversionFlags, "public int Test { get; set; }")] + [TestCase(ILSpyMainTreeViewMemberFlags, "Test : int")] + public void AutomaticProperty(ConversionFlags flags, string expectedOutput) { var prop = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetProperties(p => p.Name == "Test").Single(); - ambience.ConversionFlags = ConversionFlags.StandardConversionFlags; - string result = ambience.ConvertSymbol(prop); + ambience.ConversionFlags = flags; - Assert.AreEqual("public int Test { get; set; }", result); + Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(prop)); } - [Test] - public void Indexer() + [TestCase(StandardConversionFlags, "public int this[int index] { get; }")] + [TestCase(ILSpyMainTreeViewMemberFlags, "this[int] : int")] + public void Indexer(ConversionFlags flags, string expectedOutput) { var prop = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetProperties(p => p.IsIndexer).Single(); - ambience.ConversionFlags = ConversionFlags.StandardConversionFlags; - string result = ambience.ConvertSymbol(prop); + ambience.ConversionFlags = flags; - Assert.AreEqual("public int this[int index] { get; }", result); + Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(prop)); } #endregion #region IMethod tests - [Test] - public void ConstructorTests() + [TestCase(StandardConversionFlags, "public Program(int x);")] + [TestCase(ILSpyMainTreeViewMemberFlags, "Program(int)")] + public void ConstructorTests(ConversionFlags flags, string expectedOutput) { + var prop = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetConstructors().Single(); + ambience.ConversionFlags = flags; + + Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(prop)); + } + + [TestCase(StandardConversionFlags, "~Program();")] + [TestCase(ILSpyMainTreeViewMemberFlags, "~Program()")] + public void DestructorTests(ConversionFlags flags, string expectedOutput) + { + var dtor = compilation.FindType(typeof(CSharpAmbienceTests.Program)) + .GetMembers(m => m.SymbolKind == SymbolKind.Destructor, GetMemberOptions.IgnoreInheritedMembers).Single(); + ambience.ConversionFlags = flags; + + Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(dtor)); } #endregion diff --git a/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs index 2ae8e5b37..9f26f41e7 100644 --- a/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs +++ b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs @@ -111,6 +111,42 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem Assert.IsNull(method.AccessorOwner); } + [Test] + public void SimplePublicClassCtorTest() + { + ITypeDefinition c = GetTypeDefinition(typeof(SimplePublicClass)); + + IMethod method = c.Methods.Single(m => m.IsConstructor); + Assert.AreEqual(typeof(SimplePublicClass).FullName + "..ctor", method.FullName); + Assert.AreSame(c, method.DeclaringType); + Assert.AreEqual(Accessibility.Public, method.Accessibility); + Assert.AreEqual(SymbolKind.Constructor, method.SymbolKind); + Assert.IsFalse(method.IsVirtual); + Assert.IsFalse(method.IsStatic); + Assert.AreEqual(0, method.Parameters.Count); + Assert.AreEqual(0, method.GetAttributes().Count()); + Assert.IsTrue(method.HasBody); + Assert.IsNull(method.AccessorOwner); + } + + [Test] + public void SimplePublicClassDtorTest() + { + ITypeDefinition c = GetTypeDefinition(typeof(SimplePublicClass)); + + IMethod method = c.Methods.Single(m => m.IsDestructor); + Assert.AreEqual(typeof(SimplePublicClass).FullName + ".Finalize", method.FullName); + Assert.AreSame(c, method.DeclaringType); + Assert.AreEqual(Accessibility.Protected, method.Accessibility); + Assert.AreEqual(SymbolKind.Destructor, method.SymbolKind); + Assert.IsFalse(method.IsVirtual); + Assert.IsFalse(method.IsStatic); + Assert.AreEqual(0, method.Parameters.Count); + Assert.AreEqual(0, method.GetAttributes().Count()); + Assert.IsTrue(method.HasBody); + Assert.IsNull(method.AccessorOwner); + } + [Test] public void DynamicType() { @@ -521,6 +557,40 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem tp.DirectBaseTypes.Select(t => t.ReflectionName).ToArray()); } + [Test] + public void DtorInDerivedClass() + { + ITypeDefinition c = GetTypeDefinition(typeof(Derived<,>)); + IMethod method = c.Methods.Single(m => m.IsDestructor); + Assert.AreEqual(c.FullName + ".Finalize", method.FullName); + Assert.AreSame(c, method.DeclaringType); + Assert.AreEqual(Accessibility.Protected, method.Accessibility); + Assert.AreEqual(SymbolKind.Destructor, method.SymbolKind); + Assert.IsFalse(method.IsVirtual); + Assert.IsFalse(method.IsStatic); + Assert.AreEqual(0, method.Parameters.Count); + Assert.AreEqual(0, method.GetAttributes().Count()); + Assert.IsTrue(method.HasBody); + Assert.IsNull(method.AccessorOwner); + } + + [Test] + public void PrivateFinalizeMethodIsNotADtor() + { + ITypeDefinition c = GetTypeDefinition(typeof(TypeTestAttribute)); + IMethod method = c.Methods.Single(m => m.Name == "Finalize"); + Assert.AreEqual(c.FullName + ".Finalize", method.FullName); + Assert.AreSame(c, method.DeclaringType); + Assert.AreEqual(Accessibility.Private, 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.GetAttributes().Count()); + Assert.IsTrue(method.HasBody); + Assert.IsNull(method.AccessorOwner); + } + [Test] public void DefaultConstructorAddedToStruct() { diff --git a/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs index ee8544b04..e819918a8 100644 --- a/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs +++ b/ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs @@ -33,11 +33,21 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem public class SimplePublicClass { public void Method() { } + + public SimplePublicClass() { } + ~SimplePublicClass() { } } public class TypeTestAttribute : Attribute { public TypeTestAttribute(int a1, Type a2, Type a3) { } + +#pragma warning disable CS0465 + private void Finalize() + { + + } +#pragma warning restore CS0465 } [Params(1, StringComparison.CurrentCulture, null, 4.0, "Test")] @@ -114,10 +124,13 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem { public class Nested { } + ~Base() { } + public virtual void GenericMethodWithConstraints(T a) where X : IComparer, new() { } } public class Derived : Base { + ~Derived() { } public override void GenericMethodWithConstraints(B a) { } } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs index 905bda963..1fa81dbdd 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs @@ -60,6 +60,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation this.symbolKind = SymbolKind.Method; var (accessorOwner, semanticsAttribute) = module.PEFile.MethodSemanticsLookup.GetSemantics(handle); + const MethodAttributes finalizerAttributes = (MethodAttributes.Virtual | MethodAttributes.Family | MethodAttributes.HideBySig); if (semanticsAttribute != 0) { this.symbolKind = SymbolKind.Accessor; this.accessorOwner = accessorOwner; @@ -69,6 +70,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation this.symbolKind = SymbolKind.Constructor; else if (name.StartsWith("op_", StringComparison.Ordinal)) this.symbolKind = SymbolKind.Operator; + } else if ((attributes & finalizerAttributes) == finalizerAttributes) { + string name = this.Name; + if (name == "Finalize") { + this.symbolKind = SymbolKind.Destructor; + } } this.typeParameters = MetadataTypeParameter.Create(module, this, def.GetGenericParameters()); this.IsExtensionMethod = (attributes & MethodAttributes.Static) == MethodAttributes.Static