diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 9c11e2da2..65786faaf 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -256,6 +256,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; @@ -573,53 +587,22 @@ 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)); } } - MethodDeclaration CreateMethod(MethodDefinition methodDef) + AttributedNode CreateMethod(MethodDefinition methodDef) { // Create mapping - used in debugger MemberMapping methodMapping = methodDef.CreateCodeMapping(CSharpCodeMapping.SourceCodeMappings); @@ -646,6 +629,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; + } + } astMethod.WithAnnotation(methodMapping); return astMethod; } @@ -708,34 +707,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)); - - if (astIndexer.Getter != null && propDef.GetMethod != null) { - // Create mapping - used in debugger - MemberMapping memberMapping = propDef.GetMethod.CreateCodeMapping(CSharpCodeMapping.SourceCodeMappings); - astIndexer.Getter.WithAnnotation(memberMapping); - } - - if (astIndexer.Setter != null && propDef.SetMethod != null) { - // Create mapping - used in debugger - MemberMapping memberMapping = propDef.SetMethod.CreateCodeMapping(CSharpCodeMapping.SourceCodeMappings); - astIndexer.Setter.WithAnnotation(memberMapping); - } - - return astIndexer; - } - Modifiers FixUpVisibility(Modifiers m) { Modifiers v = m & Modifiers.VisibilityMask; @@ -749,19 +720,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); @@ -797,9 +768,55 @@ namespace ICSharpCode.Decompiler.Ast astProp.Setter.WithAnnotation(methodMapping); } 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) { 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); }