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 @@ @@ -2,16 +2,151 @@
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 Count { get; set; }
static abstract int SetterOnly { set; }
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; }
@ -24,13 +159,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceM @@ -24,13 +159,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceM
public static event EventHandler E;
public static I CreateI()
public static IAmSimple CreateI()
{
return new X();
}
}
public class X2 : I
public class X2 : IAmSimple
{
public static int Capacity {
get {
@ -61,7 +196,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceM @@ -61,7 +196,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceM
}
}
public static I CreateI()
public static IAmSimple CreateI()
{
throw new NotImplementedException();
}

2
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -1585,7 +1585,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -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);
}

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

@ -2574,6 +2574,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -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))

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

@ -159,6 +159,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -159,6 +159,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
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;
public OperatorType OperatorType {
@ -347,7 +356,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -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);
}

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

@ -1740,6 +1740,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -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 @@ -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 @@ -2255,6 +2261,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
decl.AddAnnotation(new MemberResolveResult(null, op));
}
decl.Body = GenerateBodyBlock();
decl.PrivateImplementationType = GetExplicitInterfaceType(op);
return decl;
}
@ -2373,8 +2380,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -2373,8 +2380,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
m |= Modifiers.Sealed;
}
if (member.IsAbstract && member.IsStatic)
m |= Modifiers.Abstract;
if (member.IsStatic)
{
// modifiers of static members in interfaces:
if (member.IsAbstract)
m |= Modifiers.Abstract;
else if (member.IsVirtual && !member.IsOverride)
m |= Modifiers.Virtual;
}
}
else
{

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

@ -378,10 +378,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -378,10 +378,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
static Predicate<T> FilterNonStatic<T>(Predicate<T> 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)

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

@ -576,8 +576,23 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -576,8 +576,23 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public bool IsStatic => (attributes & MethodAttributes.Static) != 0;
public bool IsAbstract => (attributes & MethodAttributes.Abstract) != 0;
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
=> (attributes & (MethodAttributes.Abstract | MethodAttributes.Virtual)) != 0
&& (attributes & MethodAttributes.Final) == 0;

Loading…
Cancel
Save