Browse Source

Implement support for explicit interface implementation of operators and operator uses.

pull/3050/head
Siegfried Pammer 2 years ago
parent
commit
591ab6b75d
  1. 105
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/StaticAbstractInterfaceMembers.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  3. 2
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  4. 13
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs
  5. 9
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  6. 6
      ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs

105
ICSharpCode.Decompiler.Tests/TestCases/Pretty/StaticAbstractInterfaceMembers.cs

@ -2,11 +2,59 @@
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceMembers namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceMembers
{ {
internal class C : I<C>
{
private string _s;
static C I<C>.P { get; set; }
static event Action I<C>.E {
add {
}
remove {
}
}
public C(string s)
{
_s = s;
}
static void I<C>.M(object x)
{
Console.WriteLine("Implementation");
}
static C I<C>.operator +(C l, C r)
{
return new C(l._s + " " + r._s);
}
static bool I<C>.operator ==(C l, C r)
{
return l._s == r._s;
}
static bool I<C>.operator !=(C l, C r)
{
return l._s != r._s;
}
static implicit I<C>.operator C(string s)
{
return new C(s);
}
static explicit I<C>.operator string(C c)
{
return c._s;
}
}
internal interface I<T> where T : I<T> internal interface I<T> where T : I<T>
{ {
static abstract T P { get; set; } static abstract T P { get; set; }
static abstract event Action E; 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 T operator +(T l, T r);
static abstract bool operator ==(T l, T r); static abstract bool 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<T> where T : IAmStatic<T> internal interface IAmStatic<T> where T : IAmStatic<T>
{ {
static int f;
static T P { get; set; } static T P { get; set; }
static event Action E; static event Action E;
static void M() static void M(object x)
{ {
} }
static T operator +(IAmStatic<T> l, T r) static IAmStatic<T> operator +(IAmStatic<T> l, IAmStatic<T> r)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
static IAmStatic()
{
f = 42;
}
} }
internal interface IAmVirtual<T> where T : IAmVirtual<T> internal interface IAmVirtual<T> where T : IAmVirtual<T>
{ {
static virtual T P { get; set; } static virtual T P { get; set; }
static virtual event Action E; static virtual event Action E;
static virtual void M() static virtual void M(object x)
{ {
} }
static virtual T operator +(T l, T r) static virtual T operator +(T l, T r)
{ {
throw new NotImplementedException(); 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>(T a, T b) where T : IAmVirtual<T>
{
T.P = a;
a = "World";
T.E += null;
T.E -= null;
T.M("Hello");
UseString((string)b);
return a + b;
}
public static IAmStatic<T> TestStaticUse<T>(T a, T b) where T : IAmStatic<T>
{
IAmStatic<T>.f = 11;
IAmStatic<T>.P = a;
IAmStatic<T>.E += null;
IAmStatic<T>.E -= null;
IAmStatic<T>.M("Hello");
return a + b;
}
public static I<T> TestAbstractStaticUse<T>(T a, T b) where T : I<T>
{
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 public class X : IAmSimple

2
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -1585,7 +1585,7 @@ namespace ICSharpCode.Decompiler.CSharp
var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings); var typeSystemAstBuilder = CreateAstBuilder(decompileRun.Settings);
var methodDecl = typeSystemAstBuilder.ConvertEntity(method); var methodDecl = typeSystemAstBuilder.ConvertEntity(method);
int lastDot = method.Name.LastIndexOf('.'); 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); methodDecl.Name = method.Name.Substring(lastDot + 1);
} }

2
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -2574,6 +2574,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
operatorDeclaration.ReturnType.AcceptVisitor(this); operatorDeclaration.ReturnType.AcceptVisitor(this);
} }
Space();
WritePrivateImplementationType(operatorDeclaration.PrivateImplementationType);
WriteKeyword(OperatorDeclaration.OperatorKeywordRole); WriteKeyword(OperatorDeclaration.OperatorKeywordRole);
Space(); Space();
if (OperatorDeclaration.IsChecked(operatorDeclaration.OperatorType)) if (OperatorDeclaration.IsChecked(operatorDeclaration.OperatorType))

13
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs

@ -159,6 +159,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return SymbolKind.Operator; } get { return SymbolKind.Operator; }
} }
/// <summary>
/// Gets/Sets the type reference of the interface that is explicitly implemented.
/// Null node if this member is not an explicit interface implementation.
/// </summary>
public AstType PrivateImplementationType {
get { return GetChildByRole(PrivateImplementationTypeRole); }
set { SetChildByRole(PrivateImplementationTypeRole, value); }
}
OperatorType operatorType; OperatorType operatorType;
public OperatorType OperatorType { public OperatorType OperatorType {
@ -347,7 +356,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{ {
OperatorDeclaration o = other as OperatorDeclaration; 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.ReturnType.DoMatch(o.ReturnType, match)
&& this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match); && this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match);
} }

9
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -1740,6 +1740,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
case SymbolKind.Event: case SymbolKind.Event:
return ConvertEvent((IEvent)entity); return ConvertEvent((IEvent)entity);
case SymbolKind.Method: case SymbolKind.Method:
if (entity.Name.Contains(".op_"))
{
goto case SymbolKind.Operator;
}
return ConvertMethod((IMethod)entity); return ConvertMethod((IMethod)entity);
case SymbolKind.Operator: case SymbolKind.Operator:
return ConvertOperator((IMethod)entity); return ConvertOperator((IMethod)entity);
@ -2225,7 +2229,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
EntityDeclaration ConvertOperator(IMethod op) 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) if (opType == null)
return ConvertMethod(op); return ConvertMethod(op);
if (opType == OperatorType.UnsignedRightShift && !SupportUnsignedRightShift) if (opType == OperatorType.UnsignedRightShift && !SupportUnsignedRightShift)
@ -2255,6 +2261,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
decl.AddAnnotation(new MemberResolveResult(null, op)); decl.AddAnnotation(new MemberResolveResult(null, op));
} }
decl.Body = GenerateBodyBlock(); decl.Body = GenerateBodyBlock();
decl.PrivateImplementationType = GetExplicitInterfaceType(op);
return decl; return decl;
} }

6
ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs

@ -378,10 +378,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
static Predicate<T> FilterNonStatic<T>(Predicate<T> filter) where T : class, IMember static Predicate<T> FilterNonStatic<T>(Predicate<T> filter) where T : class, IMember
{ {
if (filter == null) return member => (!member.IsStatic || member.SymbolKind == SymbolKind.Operator || member.IsVirtual)
return member => !member.IsStatic; && (filter == null || filter(member));
else
return member => !member.IsStatic && filter(member);
} }
public sealed override bool Equals(object obj) public sealed override bool Equals(object obj)

Loading…
Cancel
Save