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;