Browse Source

Merge pull request #3050 from icsharpcode/static-abstract-interface

Support virtual modifier on static abstract interface members
pull/3052/head
Christoph Wille 2 years ago committed by GitHub
parent
commit
b666a45df0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 147
      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. 19
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  6. 6
      ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs
  7. 19
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs

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

@ -2,16 +2,151 @@
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceMembers namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceMembers
{ {
public interface I 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>
{
static abstract T P { get; set; }
static abstract event Action E;
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);
static abstract implicit operator T(string s);
static abstract explicit operator string(T t);
}
public interface IAmSimple
{ {
static abstract int Capacity { get; } static abstract int Capacity { get; }
static abstract int Count { get; set; } static abstract int Count { get; set; }
static abstract int SetterOnly { set; } static abstract int SetterOnly { set; }
static abstract event EventHandler E; static abstract event EventHandler E;
static abstract I CreateI(); static abstract IAmSimple CreateI();
}
internal interface IAmStatic<T> where T : IAmStatic<T>
{
static int f;
static T P { get; set; }
static event Action E;
static void M(object x)
{
}
static IAmStatic<T> operator +(IAmStatic<T> l, IAmStatic<T> r)
{
throw new NotImplementedException();
}
static IAmStatic()
{
f = 42;
}
}
internal interface IAmVirtual<T> where T : IAmVirtual<T>
{
static virtual T P { get; set; }
static virtual event Action E;
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>(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 : I public class X : IAmSimple
{ {
public static int Capacity { get; } public static int Capacity { get; }
@ -24,13 +159,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceM
public static event EventHandler E; public static event EventHandler E;
public static I CreateI() public static IAmSimple CreateI()
{ {
return new X(); return new X();
} }
} }
public class X2 : I public class X2 : IAmSimple
{ {
public static int Capacity { public static int Capacity {
get { get {
@ -61,7 +196,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceM
} }
} }
public static I CreateI() public static IAmSimple CreateI()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

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);
} }

19
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;
} }
@ -2373,8 +2380,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{ {
m |= Modifiers.Sealed; m |= Modifiers.Sealed;
} }
if (member.IsAbstract && member.IsStatic) if (member.IsStatic)
m |= Modifiers.Abstract; {
// modifiers of static members in interfaces:
if (member.IsAbstract)
m |= Modifiers.Abstract;
else if (member.IsVirtual && !member.IsOverride)
m |= Modifiers.Virtual;
}
} }
else else
{ {

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)

19
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs

@ -576,8 +576,23 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public bool IsStatic => (attributes & MethodAttributes.Static) != 0; public bool IsStatic => (attributes & MethodAttributes.Static) != 0;
public bool IsAbstract => (attributes & MethodAttributes.Abstract) != 0; public bool IsAbstract => (attributes & MethodAttributes.Abstract) != 0;
public bool IsSealed => (attributes & (MethodAttributes.Abstract | MethodAttributes.Final | MethodAttributes.NewSlot | MethodAttributes.Static)) == MethodAttributes.Final; public bool IsSealed => (attributes & (MethodAttributes.Abstract | MethodAttributes.Final | MethodAttributes.NewSlot | MethodAttributes.Static)) == MethodAttributes.Final;
public bool IsVirtual => (attributes & (MethodAttributes.Abstract | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final)) == (MethodAttributes.Virtual | MethodAttributes.NewSlot);
public bool IsOverride => (attributes & (MethodAttributes.NewSlot | MethodAttributes.Virtual)) == MethodAttributes.Virtual; public bool IsVirtual {
get {
if (IsStatic)
{
return (attributes & (MethodAttributes.Abstract | MethodAttributes.Virtual)) == MethodAttributes.Virtual;
}
else
{
const MethodAttributes mask = MethodAttributes.Abstract | MethodAttributes.Virtual
| MethodAttributes.NewSlot | MethodAttributes.Final;
return (attributes & mask) == (MethodAttributes.Virtual | MethodAttributes.NewSlot);
}
}
}
public bool IsOverride => (attributes & (MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Static)) == MethodAttributes.Virtual;
public bool IsOverridable public bool IsOverridable
=> (attributes & (MethodAttributes.Abstract | MethodAttributes.Virtual)) != 0 => (attributes & (MethodAttributes.Abstract | MethodAttributes.Virtual)) != 0
&& (attributes & MethodAttributes.Final) == 0; && (attributes & MethodAttributes.Final) == 0;

Loading…
Cancel
Save