diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index aaeb49d84..328a55e30 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -231,9 +231,12 @@ namespace ICSharpCode.Decompiler.Ast int pos = name.LastIndexOf('`'); if (pos >= 0) name = name.Substring(0, pos); + pos = name.LastIndexOf('.'); + if (pos >= 0) + name = name.Substring(pos + 1); return name; } - + #region Convert Type Reference /// /// Converts a type reference. @@ -489,6 +492,7 @@ namespace ICSharpCode.Decompiler.Ast return modifiers; } + #endregion void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) @@ -503,29 +507,9 @@ namespace ICSharpCode.Decompiler.Ast foreach(EventDefinition eventDef in typeDef.Events) { astType.AddChild(CreateEvent(eventDef), TypeDeclaration.MemberRole); } - - // Add properties - foreach(PropertyDefinition propDef in typeDef.Properties) { - MemberDeclaration astProp = CreateProperty(propDef); - - if (astProp.Name == "Item" && propDef.HasParameters) - { - var defaultMember = GetDefaultMember(astType.Annotation()); - if (defaultMember.Item1 == "Item") - { - astProp = ConvertPropertyToIndexer((PropertyDeclaration)astProp, propDef); - var astAttr = astType.Attributes.SelectMany(sec => sec.Attributes).First(attr => attr.Annotation() == defaultMember.Item2); - var attrSection = (AttributeSection)astAttr.Parent; - if (attrSection.Attributes.Count == 1) - attrSection.Remove(); - else - astAttr.Remove(); - } - } - - astType.AddChild(astProp, TypeDeclaration.MemberRole); - } + // Add properties + CreateProperties(astType, typeDef); // Add constructors foreach(MethodDefinition methodDef in typeDef.Methods) { @@ -542,6 +526,35 @@ namespace ICSharpCode.Decompiler.Ast } } + private void CreateProperties(TypeDeclaration astType, TypeDefinition typeDef) + { + CustomAttribute attributeToRemove = null; + foreach (PropertyDefinition propDef in typeDef.Properties) { + MemberDeclaration astProp = CreateProperty(propDef); + + if (astProp.Name == "Item" && propDef.HasParameters) { + var defaultMember = GetDefaultMember(astType.Annotation()); + if (defaultMember.Item1 == "Item") { + astProp = ConvertPropertyToIndexer((PropertyDeclaration)astProp, propDef); + attributeToRemove = defaultMember.Item2; + } else if ((propDef.GetMethod ?? propDef.SetMethod).HasOverrides) { + astProp = ConvertPropertyToIndexer((PropertyDeclaration)astProp, propDef); + } + } + + astType.AddChild(astProp, TypeDeclaration.MemberRole); + } + + if (attributeToRemove != null) { + var astAttr = astType.Attributes.SelectMany(sec => sec.Attributes).First(attr => attr.Annotation() == attributeToRemove); + var attrSection = (AttributeSection)astAttr.Parent; + if (attrSection.Attributes.Count == 1) + attrSection.Remove(); + else + astAttr.Remove(); + } + } + MethodDeclaration CreateMethod(MethodDefinition methodDef) { MethodDeclaration astMethod = new MethodDeclaration(); @@ -552,7 +565,10 @@ namespace ICSharpCode.Decompiler.Ast astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters)); astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters)); if (!methodDef.DeclaringType.IsInterface) { - astMethod.Modifiers = ConvertModifiers(methodDef); + if (!methodDef.HasOverrides) + astMethod.Modifiers = ConvertModifiers(methodDef); + else + astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context); } ConvertAttributes(astMethod, methodDef); @@ -618,7 +634,9 @@ namespace ICSharpCode.Decompiler.Ast var astIndexer = new IndexerDeclaration(); astIndexer.Name = astProp.Name; astIndexer.CopyAnnotationsFrom(astProp); + astProp.Attributes.MoveTo(astIndexer.Attributes); astIndexer.Modifiers = astProp.Modifiers; + astIndexer.PrivateImplementationType = astProp.PrivateImplementationType.Detach(); astIndexer.ReturnType = astProp.ReturnType.Detach(); astIndexer.Getter = astProp.Getter.Detach(); astIndexer.Setter = astProp.Setter.Detach(); @@ -630,7 +648,11 @@ namespace ICSharpCode.Decompiler.Ast { PropertyDeclaration astProp = new PropertyDeclaration(); astProp.AddAnnotation(propDef); - astProp.Modifiers = ConvertModifiers(propDef.GetMethod ?? propDef.SetMethod); + var accessor = propDef.SetMethod ?? propDef.GetMethod; + if (!propDef.DeclaringType.IsInterface && !accessor.HasOverrides) { + astProp.Modifiers = ConvertModifiers(accessor); + } else if (accessor.HasOverrides) + astProp.PrivateImplementationType = ConvertType(accessor.Overrides.First().DeclaringType); astProp.Name = CleanName(propDef.Name); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); if (propDef.GetMethod != null) { diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs index d219bfee0..1a05566b4 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs @@ -358,8 +358,62 @@ namespace TargetPropertySetReturn } } } -//$$ TargetPropertyIndexSetParam -namespace TargetPropertyIndexSetParam +//$$ TargetPropertyIndexGetReturn +namespace TargetPropertyIndexGetReturn +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public int this[string s] + { + [return: MyAttribute] + get + { + return 3; + } + } + } +} +//$$ TargetPropertyIndexParamOnlySet +namespace TargetPropertyIndexParamOnlySet +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public int this[[MyAttribute] string s] + { + set + { + } + } + } +} +//$$ TargetPropertyIndexParamOnlyGet +namespace TargetPropertyIndexParamOnlyGet +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public int this[[MyAttribute] string s] + { + get + { + return 3; + } + } + } +} +//$$ TargetPropertyIndexSetReturn +namespace TargetPropertyIndexSetReturn { [AttributeUsage(AttributeTargets.All)] public class MyAttributeAttribute : Attribute @@ -373,7 +427,7 @@ namespace TargetPropertyIndexSetParam { return ""; } - [param: MyAttribute] + [return: MyAttribute] set { } diff --git a/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs b/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs index 223247bf5..240e6b0d1 100644 --- a/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs @@ -43,7 +43,8 @@ public static class DelegateConstruction public static List> AnonymousMethodStoreWithinLoop() { List> list = new List>(); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 10; i++) + { int counter; list.Add(x => counter = x); } @@ -54,7 +55,8 @@ public static class DelegateConstruction { List> list = new List>(); int counter; - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 10; i++) + { list.Add(x => counter = x); } return list; diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 42ee0a0cd..1f8fbd5be 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -57,6 +57,7 @@ + diff --git a/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs b/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs new file mode 100644 index 000000000..08193844a --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs @@ -0,0 +1,305 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +//$CS +using System; +//$CE + +//$$ IndexerWithGetOnly +namespace IndexerWithGetOnly +{ + public class MyClass + { + public int this[int i] + { + get + { + return i; + } + } + } +} +//$$ IndexerWithSetOnly +namespace IndexerWithSetOnly +{ + public class MyClass + { + public int this[int i] + { + set + { + } + } + } +} +//$$ IndexerWithMoreParameters +namespace IndexerWithMoreParameters +{ + public class MyClass + { + public int this[int i, string s, Type t] + { + get + { + return 0; + } + } + } +} +//$$ IndexerInGenericClass +namespace IndexerInGenericClass +{ + public class MyClass + { + public int this[T t] + { + get + { + return 0; + } + } + } +} +//$$ OverloadedIndexer +namespace OverloadedIndexer +{ + public class MyClass + { + public int this[int t] + { + get + { + return 0; + } + } + public int this[string s] + { + get + { + return 0; + } + set + { + Console.WriteLine(value + " " + s); + } + } + } +} +//$$ IndexerInInterface +namespace IndexerInInterface +{ + public interface IInterface + { + int this[string s, string s2] + { + set; + } + } +} +//$$ IndexerInterfaceExplicitImplementation +namespace IndexerInterfaceExplicitImplementation +{ + public interface IMyInterface + { + int this[string s] + { + get; + } + } + public class MyClass : IMyInterface + { + int IMyInterface.this[string s] + { + get + { + return 3; + } + } + } +} +//$$ IndexerInterfaceImplementation +namespace IndexerInterfaceImplementation +{ + public interface IMyInterface + { + int this[string s] + { + get; + } + } + public class MyClass : IMyInterface + { + public int this[string s] + { + get + { + return 3; + } + } + } +} +//$$ IndexerAbstract +namespace IndexerAbstract +{ + public abstract class MyClass + { + public abstract int this[string s, string s2] + { + set; + } + protected abstract string this[int index] + { + get; + } + } +} +//$$ MethodExplicit +namespace MethodExplicit +{ + public interface IMyInterface + { + void MyMethod(); + } + public class MyClass : IMyInterface + { + void IMyInterface.MyMethod() + { + } + } +} +//$$ MethodFromInterfaceVirtual +namespace MethodFromInterfaceVirtual +{ + public interface IMyInterface + { + void MyMethod(); + } + public class MyClass : IMyInterface + { + public virtual void MyMethod() + { + } + } +} +//$$ MethodFromInterface +namespace MethodFromInterface +{ + public interface IMyInterface + { + void MyMethod(); + } + public class MyClass : IMyInterface + { + public void MyMethod() + { + } + } +} +//$$ MethodFromInterfaceAbstract +namespace MethodFromInterfaceAbstract +{ + public interface IMyInterface + { + void MyMethod(); + } + public abstract class MyClass : IMyInterface + { + public abstract void MyMethod(); + } +} +//$$ PropertyInterface +namespace PropertyInterface +{ + public interface IMyInterface + { + int MyProperty + { + get; + set; + } + } +} +//$$ PropertyInterfaceExplicitImplementation +namespace PropertyInterfaceExplicitImplementation +{ + public interface IMyInterface + { + int MyProperty + { + get; + set; + } + } + public class MyClass : IMyInterface + { + int IMyInterface.MyProperty + { + get + { + return 0; + } + set + { + } + } + } +} +//$$ PropertyInterfaceImplementation +namespace PropertyInterfaceImplementation +{ + public interface IMyInterface + { + int MyProperty + { + get; + set; + } + } + public class MyClass : IMyInterface + { + public int MyProperty + { + get + { + return 0; + } + set + { + } + } + } +} +//$$ PropertyPrivateGetPublicSet +namespace PropertyPrivateGetPublicSet +{ + public class MyClass + { + public int MyProperty + { + private get + { + return 3; + } + set + { + } + } + } +} +//$$ PropertyPublicGetProtectedSet +namespace PropertyPublicGetProtectedSet +{ + public class MyClass + { + public int MyProperty + { + get + { + return 3; + } + protected set + { + } + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs index 56d7db39f..398144b2e 100644 --- a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs +++ b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs @@ -8,5 +8,10 @@ namespace ICSharpCode.Decompiler.Tests.Types { public class TypeTests : DecompilerTestBase { + [Test] + public void TypeMemberDeclarations() + { + ValidateFileRoundtrip(@"Types\S_TypeMemberDeclarations.cs"); + } } }