Browse Source

Merge pull request #2833 from icsharpcode/required-members

C# 11: Required members
pull/2839/head
Daniel Grunwald 3 years ago committed by GitHub
parent
commit
4faca0dbfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Records.cs
  2. 36
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/StaticAbstractInterfaceMembers.cs
  3. 26
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Structs.cs
  4. 12
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  5. 53
      ICSharpCode.Decompiler/CSharp/Syntax/CSharpModifierToken.cs
  6. 1
      ICSharpCode.Decompiler/CSharp/Syntax/Modifiers.cs
  7. 21
      ICSharpCode.Decompiler/DecompilerSettings.cs
  8. 7
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
  9. 9
      ILSpy/Properties/Resources.Designer.cs
  10. 3
      ILSpy/Properties/Resources.resx

25
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Records.cs

@ -129,7 +129,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
} }
#if ROSLYN4
#if CS100
internal class RecordStructs internal class RecordStructs
{ {
public record struct Base(string A); public record struct Base(string A);
@ -231,10 +232,32 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
} }
#endif #endif
#if CS110
public record struct WithRequiredMembers
{
public int A { get; set; }
public required double B { get; set; }
public object C;
public required dynamic D;
}
#endif
} }
namespace System.Runtime.CompilerServices namespace System.Runtime.CompilerServices
{ {
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
internal sealed class CompilerFeatureRequiredAttribute : Attribute
{
public CompilerFeatureRequiredAttribute(string featureName)
{
}
}
internal class IsExternalInit internal class IsExternalInit
{ {
} }
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
internal sealed class RequiredMemberAttribute : Attribute
{
}
} }

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

@ -4,11 +4,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceM
{ {
public interface I public interface I
{ {
abstract static int Capacity { get; } static abstract int Capacity { get; }
abstract static int Count { get; set; } static abstract int Count { get; set; }
abstract static int SetterOnly { set; } static abstract int SetterOnly { set; }
abstract static event EventHandler E; static abstract event EventHandler E;
abstract static I CreateI(); static abstract I CreateI();
} }
public class X : I public class X : I
@ -66,4 +66,30 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceM
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }
internal class ZOperatorTest
{
public interface IGetNext<T> where T : IGetNext<T>
{
static abstract T operator ++(T other);
}
public struct WrappedInteger : IGetNext<WrappedInteger>
{
public int Value;
public static WrappedInteger operator ++(WrappedInteger other)
{
WrappedInteger result = other;
result.Value++;
return result;
}
}
public void GenericUse<T>(T t) where T : IGetNext<T>
{
++t;
}
}
} }

26
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Structs.cs

@ -51,4 +51,28 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
} }
#endif #endif
}
#if CS110
public struct StructWithRequiredMembers
{
public required string FirstName;
public required string LastName { get; set; }
}
#endif
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
internal sealed class CompilerFeatureRequiredAttribute : Attribute
{
public CompilerFeatureRequiredAttribute(string featureName)
{
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
internal sealed class RequiredMemberAttribute : Attribute
{
}
}

12
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -1380,6 +1380,10 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
} }
if (settings.RequiredMembers)
{
RemoveAttribute(typeDecl, KnownAttribute.RequiredAttribute);
}
if (typeDecl.ClassType == ClassType.Enum) if (typeDecl.ClassType == ClassType.Enum)
{ {
switch (decompileRun.EnumValueDisplayMode) switch (decompileRun.EnumValueDisplayMode)
@ -1871,6 +1875,10 @@ namespace ICSharpCode.Decompiler.CSharp
typeSystemAstBuilder.UseSpecialConstants = !(field.DeclaringType.Equals(field.ReturnType) || isMathPIOrE); typeSystemAstBuilder.UseSpecialConstants = !(field.DeclaringType.Equals(field.ReturnType) || isMathPIOrE);
var fieldDecl = typeSystemAstBuilder.ConvertEntity(field); var fieldDecl = typeSystemAstBuilder.ConvertEntity(field);
SetNewModifier(fieldDecl); SetNewModifier(fieldDecl);
if (settings.RequiredMembers && RemoveAttribute(fieldDecl, KnownAttribute.RequiredAttribute))
{
fieldDecl.Modifiers |= Modifiers.Required;
}
if (settings.FixedBuffers && IsFixedField(field, out var elementType, out var elementCount)) if (settings.FixedBuffers && IsFixedField(field, out var elementType, out var elementCount))
{ {
var fixedFieldDecl = new FixedFieldDeclaration(); var fixedFieldDecl = new FixedFieldDeclaration();
@ -1983,6 +1991,10 @@ namespace ICSharpCode.Decompiler.CSharp
propertyDecl.Modifiers &= ~(Modifiers.New | Modifiers.Virtual); propertyDecl.Modifiers &= ~(Modifiers.New | Modifiers.Virtual);
propertyDecl.Modifiers |= Modifiers.Override; propertyDecl.Modifiers |= Modifiers.Override;
} }
if (settings.RequiredMembers && RemoveAttribute(propertyDecl, KnownAttribute.RequiredAttribute))
{
propertyDecl.Modifiers |= Modifiers.Required;
}
return propertyDecl; return propertyDecl;
} }
catch (Exception innerException) when (!(innerException is OperationCanceledException || innerException is DecompilerException)) catch (Exception innerException) when (!(innerException is OperationCanceledException || innerException is DecompilerException))

53
ICSharpCode.Decompiler/CSharp/Syntax/CSharpModifierToken.cs

@ -66,8 +66,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
Modifiers.Public, Modifiers.Private, Modifiers.Protected, Modifiers.Internal, Modifiers.Public, Modifiers.Private, Modifiers.Protected, Modifiers.Internal,
Modifiers.New, Modifiers.New,
Modifiers.Unsafe, Modifiers.Unsafe,
Modifiers.Abstract, Modifiers.Virtual, Modifiers.Sealed, Modifiers.Static, Modifiers.Override, Modifiers.Static, Modifiers.Abstract, Modifiers.Virtual, Modifiers.Sealed, Modifiers.Override,
Modifiers.Readonly, Modifiers.Volatile, Modifiers.Required, Modifiers.Readonly, Modifiers.Volatile,
Modifiers.Ref, Modifiers.Ref,
Modifiers.Extern, Modifiers.Partial, Modifiers.Const, Modifiers.Extern, Modifiers.Partial, Modifiers.Const,
Modifiers.Async, Modifiers.Async,
@ -119,6 +119,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return "async"; return "async";
case Modifiers.Ref: case Modifiers.Ref:
return "ref"; return "ref";
case Modifiers.Required:
return "required";
case Modifiers.Any: case Modifiers.Any:
// even though it's used for pattern matching only, 'any' needs to be in this list to be usable in the AST // even though it's used for pattern matching only, 'any' needs to be in this list to be usable in the AST
return "any"; return "any";
@ -129,50 +131,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static int GetModifierLength(Modifiers modifier) public static int GetModifierLength(Modifiers modifier)
{ {
switch (modifier) return GetModifierName(modifier).Length;
{
case Modifiers.Private:
return "private".Length;
case Modifiers.Internal:
return "internal".Length;
case Modifiers.Protected:
return "protected".Length;
case Modifiers.Public:
return "public".Length;
case Modifiers.Abstract:
return "abstract".Length;
case Modifiers.Virtual:
return "virtual".Length;
case Modifiers.Sealed:
return "sealed".Length;
case Modifiers.Static:
return "static".Length;
case Modifiers.Override:
return "override".Length;
case Modifiers.Readonly:
return "readonly".Length;
case Modifiers.Const:
return "const".Length;
case Modifiers.New:
return "new".Length;
case Modifiers.Partial:
return "partial".Length;
case Modifiers.Extern:
return "extern".Length;
case Modifiers.Volatile:
return "volatile".Length;
case Modifiers.Unsafe:
return "unsafe".Length;
case Modifiers.Async:
return "async".Length;
case Modifiers.Ref:
return "ref".Length;
case Modifiers.Any:
// even though it's used for pattern matching only, 'any' needs to be in this list to be usable in the AST
return "any".Length;
default:
throw new NotSupportedException("Invalid value for Modifiers");
}
} }
public static Modifiers GetModifierValue(string modifier) public static Modifiers GetModifierValue(string modifier)
@ -215,6 +174,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return Modifiers.Async; return Modifiers.Async;
case "ref": case "ref":
return Modifiers.Ref; return Modifiers.Ref;
case "required":
return Modifiers.Required;
case "any": case "any":
// even though it's used for pattern matching only, 'any' needs to be in this list to be usable in the AST // even though it's used for pattern matching only, 'any' needs to be in this list to be usable in the AST
return Modifiers.Any; return Modifiers.Any;

1
ICSharpCode.Decompiler/CSharp/Syntax/Modifiers.cs

@ -55,6 +55,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
Unsafe = 0x8000, Unsafe = 0x8000,
Async = 0x10000, Async = 0x10000,
Ref = 0x20000, Ref = 0x20000,
Required = 0x40000,
VisibilityMask = Private | Internal | Protected | Public, VisibilityMask = Private | Internal | Protected | Public,

21
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -151,12 +151,13 @@ namespace ICSharpCode.Decompiler
{ {
parameterNullCheck = false; parameterNullCheck = false;
lifetimeAnnotations = false; lifetimeAnnotations = false;
requiredMembers = false;
} }
} }
public CSharp.LanguageVersion GetMinimumRequiredVersion() public CSharp.LanguageVersion GetMinimumRequiredVersion()
{ {
if (parameterNullCheck || lifetimeAnnotations) if (parameterNullCheck || lifetimeAnnotations || requiredMembers)
return CSharp.LanguageVersion.CSharp11_0; return CSharp.LanguageVersion.CSharp11_0;
if (fileScopedNamespaces || recordStructs) if (fileScopedNamespaces || recordStructs)
return CSharp.LanguageVersion.CSharp10_0; return CSharp.LanguageVersion.CSharp10_0;
@ -356,6 +357,24 @@ namespace ICSharpCode.Decompiler
} }
} }
bool requiredMembers = true;
/// <summary>
/// Use C# 11 <c>required</c> modifier.
/// </summary>
[Category("C# 11.0 / VS 2022.4")]
[Description("DecompilerSettings.RequiredMembers")]
public bool RequiredMembers {
get { return requiredMembers; }
set {
if (requiredMembers != value)
{
requiredMembers = value;
OnPropertyChanged();
}
}
}
bool switchExpressions = true; bool switchExpressions = true;
/// <summary> /// <summary>

7
ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs

@ -106,11 +106,14 @@ namespace ICSharpCode.Decompiler.TypeSystem
// C# 9 attributes: // C# 9 attributes:
NativeInteger, NativeInteger,
PreserveBaseOverrides, PreserveBaseOverrides,
// C# 11 attributes:
RequiredAttribute,
} }
public static class KnownAttributes public static class KnownAttributes
{ {
internal const int Count = (int)KnownAttribute.PreserveBaseOverrides + 1; internal const int Count = (int)KnownAttribute.RequiredAttribute + 1;
static readonly TopLevelTypeName[] typeNames = new TopLevelTypeName[Count]{ static readonly TopLevelTypeName[] typeNames = new TopLevelTypeName[Count]{
default, default,
@ -175,6 +178,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
// C# 9 attributes: // C# 9 attributes:
new TopLevelTypeName("System.Runtime.CompilerServices", "NativeIntegerAttribute"), new TopLevelTypeName("System.Runtime.CompilerServices", "NativeIntegerAttribute"),
new TopLevelTypeName("System.Runtime.CompilerServices", "PreserveBaseOverridesAttribute"), new TopLevelTypeName("System.Runtime.CompilerServices", "PreserveBaseOverridesAttribute"),
// C# 11 attributes:
new TopLevelTypeName("System.Runtime.CompilerServices", "RequiredMemberAttribute"),
}; };
public static ref readonly TopLevelTypeName GetTypeName(this KnownAttribute attr) public static ref readonly TopLevelTypeName GetTypeName(this KnownAttribute attr)

9
ILSpy/Properties/Resources.Designer.cs generated

@ -1226,6 +1226,15 @@ namespace ICSharpCode.ILSpy.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to Required members.
/// </summary>
public static string DecompilerSettings_RequiredMembers {
get {
return ResourceManager.GetString("DecompilerSettings.RequiredMembers", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Separate local variable declarations and initializers (int x = 5; -&gt; int x; x = 5;), if possible. /// Looks up a localized string similar to Separate local variable declarations and initializers (int x = 5; -&gt; int x; x = 5;), if possible.
/// </summary> /// </summary>

3
ILSpy/Properties/Resources.resx

@ -1054,4 +1054,7 @@ Do you want to continue?</value>
<data name="_Window" xml:space="preserve"> <data name="_Window" xml:space="preserve">
<value>_Window</value> <value>_Window</value>
</data> </data>
<data name="DecompilerSettings.RequiredMembers" xml:space="preserve">
<value>Required members</value>
</data>
</root> </root>
Loading…
Cancel
Save