From 63e11492a6682ee1c03e28a14c1f29451d311283 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 4 Apr 2011 17:26:40 +0200 Subject: [PATCH 1/3] Fixed decompilation of indexers (when decompiling the member, not the whole type) --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 126 +++++++++++++---------- 1 file changed, 70 insertions(+), 56 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 37fbb8f9c..53e675d8b 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -248,6 +248,20 @@ namespace ICSharpCode.Decompiler.Ast AddTypeMembers(astType, typeDef); + + if (astType.Members.Any(m => m is IndexerDeclaration)) { + // Remove the [DefaultMember] attribute if the class contains indexers + foreach (AttributeSection section in astType.Attributes) { + foreach (Ast.Attribute attr in section.Attributes) { + TypeReference tr = attr.Type.Annotation(); + if (tr != null && tr.Name == "DefaultMemberAttribute" && tr.Namespace == "System.Reflection") { + attr.Remove(); + } + } + if (section.Attributes.Count == 0) + section.Remove(); + } + } } context.CurrentType = oldCurrentType; @@ -565,49 +579,18 @@ namespace ICSharpCode.Decompiler.Ast } // Add properties - CreateProperties(astType, typeDef); - - // Add constructors - foreach(MethodDefinition methodDef in typeDef.Methods) { - if (!methodDef.IsConstructor) continue; - - astType.AddChild(CreateConstructor(methodDef), TypeDeclaration.MemberRole); + foreach(PropertyDefinition propDef in typeDef.Properties) { + astType.Members.Add(CreateProperty(propDef)); } // Add methods foreach(MethodDefinition methodDef in typeDef.Methods) { - if (methodDef.IsConstructor || MemberIsHidden(methodDef, context.Settings)) continue; + if (MemberIsHidden(methodDef, context.Settings)) continue; - astType.AddChild(CreateMethod(methodDef), TypeDeclaration.MemberRole); - } - } - - 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(); + if (methodDef.IsConstructor) + astType.Members.Add(CreateConstructor(methodDef)); else - astAttr.Remove(); + astType.Members.Add(CreateMethod(methodDef)); } } @@ -692,21 +675,6 @@ namespace ICSharpCode.Decompiler.Ast return astMethod; } - IndexerDeclaration ConvertPropertyToIndexer(PropertyDeclaration astProp, PropertyDefinition propDef) - { - 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(); - astIndexer.Parameters.AddRange(MakeParameters(propDef.Parameters)); - return astIndexer; - } - Modifiers FixUpVisibility(Modifiers m) { Modifiers v = m & Modifiers.VisibilityMask; @@ -720,19 +688,19 @@ namespace ICSharpCode.Decompiler.Ast return m & ~Modifiers.Private; } - PropertyDeclaration CreateProperty(PropertyDefinition propDef) + MemberDeclaration CreateProperty(PropertyDefinition propDef) { PropertyDeclaration astProp = new PropertyDeclaration(); astProp.AddAnnotation(propDef); var accessor = propDef.GetMethod ?? propDef.SetMethod; Modifiers getterModifiers = Modifiers.None; Modifiers setterModifiers = Modifiers.None; - if (!propDef.DeclaringType.IsInterface && !accessor.HasOverrides) { + if (accessor.HasOverrides) { + astProp.PrivateImplementationType = ConvertType(accessor.Overrides.First().DeclaringType); + } else if (!propDef.DeclaringType.IsInterface) { getterModifiers = ConvertModifiers(propDef.GetMethod); setterModifiers = ConvertModifiers(propDef.SetMethod); astProp.Modifiers = FixUpVisibility(getterModifiers | setterModifiers); - } else if (accessor.HasOverrides) { - astProp.PrivateImplementationType = ConvertType(accessor.Overrides.First().DeclaringType); } astProp.Name = CleanName(propDef.Name); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); @@ -756,9 +724,55 @@ namespace ICSharpCode.Decompiler.Ast astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask; } ConvertCustomAttributes(astProp, propDef); + + // Check whether the property is an indexer: + if (propDef.HasParameters) { + PropertyDefinition basePropDef = propDef; + if (accessor.HasOverrides) { + // if the property is explicitly implementing an interface, look up the property in the interface: + MethodDefinition baseAccessor = accessor.Overrides.First().Resolve(); + if (baseAccessor != null) { + foreach (PropertyDefinition baseProp in baseAccessor.DeclaringType.Properties) { + if (baseProp.GetMethod == baseAccessor || baseProp.SetMethod == baseAccessor) { + basePropDef = baseProp; + break; + } + } + } + } + // figure out the name of the indexer: + string defaultMemberName = null; + var defaultMemberAttribute = basePropDef.DeclaringType.CustomAttributes.FirstOrDefault(IsDefaultMemberAttribute); + if (defaultMemberAttribute != null && defaultMemberAttribute.ConstructorArguments.Count == 1) { + defaultMemberName = defaultMemberAttribute.ConstructorArguments[0].Value as string; + } + if (basePropDef.Name == defaultMemberName) { + return ConvertPropertyToIndexer(astProp, propDef); + } + } return astProp; } + bool IsDefaultMemberAttribute(CustomAttribute ca) + { + return ca.AttributeType.Name == "DefaultMemberAttribute" && ca.AttributeType.Namespace == "System.Reflection"; + } + + IndexerDeclaration ConvertPropertyToIndexer(PropertyDeclaration astProp, PropertyDefinition propDef) + { + 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(); + astIndexer.Parameters.AddRange(MakeParameters(propDef.Parameters)); + return astIndexer; + } + AttributedNode CreateEvent(EventDefinition eventDef) { if (eventDef.AddMethod != null && eventDef.AddMethod.IsAbstract) { From edf5f6711e23854a84d0c27b359cc8fc601ac557 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 4 Apr 2011 17:47:53 +0200 Subject: [PATCH 2/3] Add OperatorDeclaration.GetOperatorType() helper method. --- .../Ast/TypeMembers/OperatorDeclaration.cs | 72 ++++++++++++------- .../CSharp/OutputVisitor/OutputVisitor.cs | 6 +- .../CSharp/Parser/CSharpParser.cs | 20 +----- 3 files changed, 50 insertions(+), 48 deletions(-) diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs index 7215412eb..c7e68ab02 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs @@ -29,41 +29,45 @@ using System.Linq; namespace ICSharpCode.NRefactory.CSharp { - public enum OperatorType { + public enum OperatorType + { + // Values must correspond to Mono.CSharp.Operator.OpType + // due to the casts used in OperatorDeclaration. + // Unary operators - LogicalNot, - OnesComplement, - Increment, - Decrement, - True, - False, + LogicalNot = Mono.CSharp.Operator.OpType.LogicalNot, + OnesComplement = Mono.CSharp.Operator.OpType.OnesComplement, + Increment = Mono.CSharp.Operator.OpType.Increment, + Decrement = Mono.CSharp.Operator.OpType.Decrement, + True = Mono.CSharp.Operator.OpType.True, + False = Mono.CSharp.Operator.OpType.False, // Unary and Binary operators - Addition, - Subtraction, + Addition = Mono.CSharp.Operator.OpType.Addition, + Subtraction = Mono.CSharp.Operator.OpType.Subtraction, - UnaryPlus, - UnaryNegation, + UnaryPlus = Mono.CSharp.Operator.OpType.UnaryPlus, + UnaryNegation = Mono.CSharp.Operator.OpType.UnaryNegation, // Binary operators - Multiply, - Division, - Modulus, - BitwiseAnd, - BitwiseOr, - ExclusiveOr, - LeftShift, - RightShift, - Equality, - Inequality, - GreaterThan, - LessThan, - GreaterThanOrEqual, - LessThanOrEqual, + Multiply = Mono.CSharp.Operator.OpType.Multiply, + Division = Mono.CSharp.Operator.OpType.Division, + Modulus = Mono.CSharp.Operator.OpType.Modulus, + BitwiseAnd = Mono.CSharp.Operator.OpType.BitwiseAnd, + BitwiseOr = Mono.CSharp.Operator.OpType.BitwiseOr, + ExclusiveOr = Mono.CSharp.Operator.OpType.ExclusiveOr, + LeftShift = Mono.CSharp.Operator.OpType.LeftShift, + RightShift = Mono.CSharp.Operator.OpType.RightShift, + Equality = Mono.CSharp.Operator.OpType.Equality, + Inequality = Mono.CSharp.Operator.OpType.Inequality, + GreaterThan = Mono.CSharp.Operator.OpType.GreaterThan, + LessThan = Mono.CSharp.Operator.OpType.LessThan, + GreaterThanOrEqual = Mono.CSharp.Operator.OpType.GreaterThanOrEqual, + LessThanOrEqual = Mono.CSharp.Operator.OpType.LessThanOrEqual, // Implicit and Explicit - Implicit, - Explicit + Implicit = Mono.CSharp.Operator.OpType.Implicit, + Explicit = Mono.CSharp.Operator.OpType.Explicit } public class OperatorDeclaration : AttributedNode @@ -98,11 +102,25 @@ namespace ICSharpCode.NRefactory.CSharp set { SetChildByRole (Roles.Body, value); } } + /// + /// Gets the operator type from the method name, or null, if the method does not represent one of the known operator types. + /// + public static OperatorType? GetOperatorType(string methodName) + { + return (OperatorType?)Mono.CSharp.Operator.GetType(methodName); + } + + /// + /// Gets the method name for the operator type. ("op_Addition", "op_Implicit", etc.) + /// public static string GetName(OperatorType type) { return Mono.CSharp.Operator.GetMetadataName((Mono.CSharp.Operator.OpType)type); } + /// + /// Gets the token for the operator type ("+", "implicit", etc.) + /// public static string GetToken(OperatorType type) { return Mono.CSharp.Operator.GetName((Mono.CSharp.Operator.OpType)type); diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index e8a9f408f..73364abf8 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -1626,8 +1626,10 @@ namespace ICSharpCode.NRefactory.CSharp LPar(); Space(policy.SpacesWithinCatchParentheses); catchClause.Type.AcceptVisitor(this, data); - Space(); - WriteIdentifier(catchClause.VariableName); + if (!string.IsNullOrEmpty(catchClause.VariableName)) { + Space(); + WriteIdentifier(catchClause.VariableName); + } Space(policy.SpacesWithinCatchParentheses); RPar(); } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs index f9a20b45b..9cbb70a76 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs @@ -551,25 +551,7 @@ namespace ICSharpCode.NRefactory.CSharp if (location != null) newOperator.AddChild (new CSharpTokenNode (Convert (location[0]), "operator".Length), OperatorDeclaration.OperatorKeywordRole); - int opLength = 1; - switch (newOperator.OperatorType) { - case OperatorType.LeftShift: - case OperatorType.RightShift: - case OperatorType.LessThanOrEqual: - case OperatorType.GreaterThanOrEqual: - case OperatorType.Equality: - case OperatorType.Inequality: -// case OperatorType.LogicalAnd: -// case OperatorType.LogicalOr: - opLength = 2; - break; - case OperatorType.True: - opLength = "true".Length; - break; - case OperatorType.False: - opLength = "false".Length; - break; - } + int opLength = OperatorDeclaration.GetToken(newOperator.OperatorType).Length; if (location != null) newOperator.AddChild (new CSharpTokenNode (Convert (location[1]), opLength), OperatorDeclaration.OperatorTypeRole); } From 2e4f0411cddec98d20309cceec4014597e7e116e Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 4 Apr 2011 18:23:35 +0200 Subject: [PATCH 3/3] Use operator syntax when decompiling operator methods. Closes #103. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 53e675d8b..810f3b774 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -594,7 +594,7 @@ namespace ICSharpCode.Decompiler.Ast } } - MethodDeclaration CreateMethod(MethodDefinition methodDef) + AttributedNode CreateMethod(MethodDefinition methodDef) { MethodDeclaration astMethod = new MethodDeclaration(); astMethod.AddAnnotation(methodDef); @@ -618,6 +618,22 @@ namespace ICSharpCode.Decompiler.Ast } } } + + // Convert MethodDeclaration to OperatorDeclaration if possible + if (methodDef.IsSpecialName && !methodDef.HasGenericParameters) { + OperatorType? opType = OperatorDeclaration.GetOperatorType(methodDef.Name); + if (opType.HasValue) { + OperatorDeclaration op = new OperatorDeclaration(); + op.CopyAnnotationsFrom(astMethod); + op.ReturnType = astMethod.ReturnType.Detach(); + op.OperatorType = opType.Value; + op.Modifiers = astMethod.Modifiers; + astMethod.Parameters.MoveTo(op.Parameters); + astMethod.Attributes.MoveTo(op.Attributes); + op.Body = astMethod.Body.Detach(); + return op; + } + } return astMethod; }