diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/StaticAbstractInterfaceMembers.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/StaticAbstractInterfaceMembers.cs index 4a6bc0d2b..7d0b6ed5e 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/StaticAbstractInterfaceMembers.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/StaticAbstractInterfaceMembers.cs @@ -2,11 +2,59 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceMembers { + internal class C : I + { + private string _s; + + static C I.P { get; set; } + static event Action I.E { + add { + + } + remove { + + } + } + public C(string s) + { + _s = s; + } + + static void I.M(object x) + { + Console.WriteLine("Implementation"); + } + static C I.operator +(C l, C r) + { + return new C(l._s + " " + r._s); + } + + static bool I.operator ==(C l, C r) + { + return l._s == r._s; + } + + static bool I.operator !=(C l, C r) + { + return l._s != r._s; + } + + static implicit I.operator C(string s) + { + return new C(s); + } + + static explicit I.operator string(C c) + { + return c._s; + } + } + internal interface I where T : I { static abstract T P { get; set; } static abstract event Action E; - static abstract void M(); + static abstract void M(object x); static abstract T operator +(T l, T r); static abstract bool operator ==(T l, T r); static abstract bool operator !=(T l, T r); @@ -25,28 +73,77 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceM internal interface IAmStatic where T : IAmStatic { + static int f; static T P { get; set; } static event Action E; - static void M() + static void M(object x) { } - static T operator +(IAmStatic l, T r) + static IAmStatic operator +(IAmStatic l, IAmStatic r) { throw new NotImplementedException(); } + static IAmStatic() + { + f = 42; + } } internal interface IAmVirtual where T : IAmVirtual { static virtual T P { get; set; } static virtual event Action E; - static virtual void M() + static virtual void M(object x) { } static virtual T operator +(T l, T r) { throw new NotImplementedException(); } + static virtual implicit operator T(string s) + { + return default(T); + } + static virtual explicit operator string(T t) + { + return null; + } + } + + internal class Uses + { + public static T TestVirtualStaticUse(T a, T b) where T : IAmVirtual + { + T.P = a; + a = "World"; + T.E += null; + T.E -= null; + T.M("Hello"); + UseString((string)b); + return a + b; + } + public static IAmStatic TestStaticUse(T a, T b) where T : IAmStatic + { + IAmStatic.f = 11; + IAmStatic.P = a; + IAmStatic.E += null; + IAmStatic.E -= null; + IAmStatic.M("Hello"); + return a + b; + } + public static I TestAbstractStaticUse(T a, T b) where T : I + { + T.P = a; + a = "World"; + T.E += null; + T.E -= null; + T.M("Hello"); + UseString((string)b); + return a + b; + } + private static void UseString(string a) + { + } } public class X : IAmSimple diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 266540cb9..bd9ecd13e 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -1585,7 +1585,7 @@ namespace ICSharpCode.Decompiler.CSharp var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings); var methodDecl = typeSystemAstBuilder.ConvertEntity(method); int lastDot = method.Name.LastIndexOf('.'); - if (method.IsExplicitInterfaceImplementation && lastDot >= 0) + if (methodDecl is not OperatorDeclaration && method.IsExplicitInterfaceImplementation && lastDot >= 0) { methodDecl.Name = method.Name.Substring(lastDot + 1); } diff --git a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs index 7fee876ca..66e6a2acf 100644 --- a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs +++ b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs @@ -2574,6 +2574,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor { operatorDeclaration.ReturnType.AcceptVisitor(this); } + Space(); + WritePrivateImplementationType(operatorDeclaration.PrivateImplementationType); WriteKeyword(OperatorDeclaration.OperatorKeywordRole); Space(); if (OperatorDeclaration.IsChecked(operatorDeclaration.OperatorType)) diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs index de3915b83..9ffc9058b 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs @@ -159,6 +159,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax get { return SymbolKind.Operator; } } + /// + /// Gets/Sets the type reference of the interface that is explicitly implemented. + /// Null node if this member is not an explicit interface implementation. + /// + public AstType PrivateImplementationType { + get { return GetChildByRole(PrivateImplementationTypeRole); } + set { SetChildByRole(PrivateImplementationTypeRole, value); } + } + OperatorType operatorType; public OperatorType OperatorType { @@ -347,7 +356,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { OperatorDeclaration o = other as OperatorDeclaration; - return o != null && this.MatchAttributesAndModifiers(o, match) && this.OperatorType == o.OperatorType + return o != null && this.MatchAttributesAndModifiers(o, match) + && this.PrivateImplementationType.DoMatch(o.PrivateImplementationType, match) + && this.OperatorType == o.OperatorType && this.ReturnType.DoMatch(o.ReturnType, match) && this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match); } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index 57415625b..799e79035 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -1740,6 +1740,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax case SymbolKind.Event: return ConvertEvent((IEvent)entity); case SymbolKind.Method: + if (entity.Name.Contains(".op_")) + { + goto case SymbolKind.Operator; + } return ConvertMethod((IMethod)entity); case SymbolKind.Operator: return ConvertOperator((IMethod)entity); @@ -2225,7 +2229,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax EntityDeclaration ConvertOperator(IMethod op) { - OperatorType? opType = OperatorDeclaration.GetOperatorType(op.Name); + int dot = op.Name.LastIndexOf('.'); + string name = op.Name.Substring(dot + 1); + OperatorType? opType = OperatorDeclaration.GetOperatorType(name); if (opType == null) return ConvertMethod(op); if (opType == OperatorType.UnsignedRightShift && !SupportUnsignedRightShift) @@ -2255,6 +2261,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax decl.AddAnnotation(new MemberResolveResult(null, op)); } decl.Body = GenerateBodyBlock(); + decl.PrivateImplementationType = GetExplicitInterfaceType(op); return decl; } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs index 0660573f0..289fc35e7 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs @@ -378,10 +378,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation static Predicate FilterNonStatic(Predicate filter) where T : class, IMember { - if (filter == null) - return member => !member.IsStatic; - else - return member => !member.IsStatic && filter(member); + return member => (!member.IsStatic || member.SymbolKind == SymbolKind.Operator || member.IsVirtual) + && (filter == null || filter(member)); } public sealed override bool Equals(object obj)