diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
index 28f844d39..31f8726a1 100644
--- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -108,6 +108,7 @@
+
diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
index c35fd8b78..c2195eee9 100644
--- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
@@ -627,6 +627,12 @@ namespace ICSharpCode.Decompiler.Tests
RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview);
}
+ [Test]
+ public void StaticAbstractInterfaceMembers([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions)
+ {
+ RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview | CompilerOptions.ReferenceCore);
+ }
+
void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null)
{
Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings);
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InterfaceTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InterfaceTests.cs
index 405bad19a..65591278d 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InterfaceTests.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InterfaceTests.cs
@@ -24,6 +24,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public interface IA
{
+#if CS80
+ static int Field;
+#endif
int Property1 { get; }
int Property2 { set; }
int Property3 { get; set; }
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/StaticAbstractInterfaceMembers.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/StaticAbstractInterfaceMembers.cs
new file mode 100644
index 000000000..6b5081ca5
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/StaticAbstractInterfaceMembers.cs
@@ -0,0 +1,69 @@
+using System;
+
+namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceMembers
+{
+ public interface I
+ {
+ abstract static int Capacity { get; }
+ abstract static int Count { get; set; }
+ abstract static int SetterOnly { set; }
+ abstract static event EventHandler E;
+ abstract static I CreateI();
+ }
+
+ public class X : I
+ {
+ public static int Capacity { get; }
+
+ public static int Count { get; set; }
+
+ public static int SetterOnly {
+ set {
+ }
+ }
+
+ public static event EventHandler E;
+
+ public static I CreateI()
+ {
+ return new X();
+ }
+ }
+
+ public class X2 : I
+ {
+ public static int Capacity {
+ get {
+ throw new NotImplementedException();
+ }
+ }
+
+ public static int Count {
+ get {
+ throw new NotImplementedException();
+ }
+ set {
+ throw new NotImplementedException();
+ }
+ }
+ public static int SetterOnly {
+ set {
+ throw new NotImplementedException();
+ }
+ }
+
+ public static event EventHandler E {
+ add {
+ throw new NotImplementedException();
+ }
+ remove {
+ throw new NotImplementedException();
+ }
+ }
+
+ public static I CreateI()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
index 5faffd703..b4e814627 100644
--- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
@@ -1073,6 +1073,10 @@ namespace ICSharpCode.Decompiler.CSharp
{
yield break; // cannot create forwarder for existing explicit interface impl
}
+ if (method.IsStatic)
+ {
+ yield break; // cannot create forwarder for static interface impl
+ }
var genericContext = new Decompiler.TypeSystem.GenericContext(method);
var methodHandle = (MethodDefinitionHandle)method.MetadataToken;
foreach (var h in methodHandle.GetMethodImplementations(metadata))
@@ -1464,7 +1468,8 @@ namespace ICSharpCode.Decompiler.CSharp
{
methodDecl.Modifiers |= Modifiers.Extern;
}
- if (method.SymbolKind == SymbolKind.Method && !method.IsExplicitInterfaceImplementation && methodDefinition.HasFlag(System.Reflection.MethodAttributes.Virtual) == methodDefinition.HasFlag(System.Reflection.MethodAttributes.NewSlot))
+ if (method.SymbolKind == SymbolKind.Method && !method.IsExplicitInterfaceImplementation
+ && methodDefinition.HasFlag(System.Reflection.MethodAttributes.Virtual) == methodDefinition.HasFlag(System.Reflection.MethodAttributes.NewSlot))
{
SetNewModifier(methodDecl);
}
diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
index a850c6362..d2d04a23d 100644
--- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
@@ -2312,17 +2312,29 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
m |= Modifiers.Static;
}
}
- else if (member.IsStatic)
- {
- m |= Modifiers.Static;
- }
else
{
+ if (member.IsStatic)
+ {
+ m |= Modifiers.Static;
+ }
+ if (member is IMethod method && method.ThisIsRefReadOnly
+ && method.DeclaringTypeDefinition?.IsReadOnly == false)
+ {
+ m |= Modifiers.Readonly;
+ }
+
var declaringType = member.DeclaringType;
if (declaringType.Kind == TypeKind.Interface)
{
- if (!member.IsVirtual && !member.IsAbstract && !member.IsOverride && member.Accessibility != Accessibility.Private && member is IMethod method2 && method2.HasBody)
+ if (!member.IsStatic && !member.IsVirtual && !member.IsAbstract && !member.IsOverride
+ && member.Accessibility != Accessibility.Private
+ && member is IMethod method2 && method2.HasBody)
+ {
m |= Modifiers.Sealed;
+ }
+ if (member.IsAbstract && member.IsStatic)
+ m |= Modifiers.Abstract;
}
else
{
@@ -2330,13 +2342,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
m |= Modifiers.Abstract;
else if (member.IsVirtual && !member.IsOverride)
m |= Modifiers.Virtual;
+ if (member.IsOverride && !member.IsExplicitInterfaceImplementation)
+ m |= Modifiers.Override;
+ if (member.IsSealed && !member.IsExplicitInterfaceImplementation)
+ m |= Modifiers.Sealed;
}
- if (member.IsOverride && !member.IsExplicitInterfaceImplementation)
- m |= Modifiers.Override;
- if (member.IsSealed && !member.IsExplicitInterfaceImplementation)
- m |= Modifiers.Sealed;
- if (member is IMethod method && method.ThisIsRefReadOnly && method.DeclaringTypeDefinition?.IsReadOnly == false)
- m |= Modifiers.Readonly;
}
}
return m;