Browse Source

Add support for C# 11 required members.

pull/2833/head
Daniel Grunwald 3 years ago
parent
commit
f3013010cd
  1. 6
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Records.cs
  2. 26
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Structs.cs
  3. 12
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  4. 51
      ICSharpCode.Decompiler/CSharp/Syntax/CSharpModifierToken.cs
  5. 1
      ICSharpCode.Decompiler/CSharp/Syntax/Modifiers.cs
  6. 21
      ICSharpCode.Decompiler/DecompilerSettings.cs
  7. 7
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
  8. 9
      ILSpy/Properties/Resources.Designer.cs
  9. 3
      ILSpy/Properties/Resources.resx

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

@ -129,7 +129,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -129,7 +129,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
#if ROSLYN4
#if CS100
internal class RecordStructs
{
public record struct Base(string A);
@ -230,6 +231,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -230,6 +231,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
}
#endif
#if CS110
#endif
}
namespace System.Runtime.CompilerServices

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

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

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

@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
Modifiers.New,
Modifiers.Unsafe,
Modifiers.Abstract, Modifiers.Virtual, Modifiers.Sealed, Modifiers.Static, Modifiers.Override,
Modifiers.Readonly, Modifiers.Volatile,
Modifiers.Required, Modifiers.Readonly, Modifiers.Volatile,
Modifiers.Ref,
Modifiers.Extern, Modifiers.Partial, Modifiers.Const,
Modifiers.Async,
@ -119,6 +119,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -119,6 +119,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return "async";
case Modifiers.Ref:
return "ref";
case Modifiers.Required:
return "required";
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";
@ -129,50 +131,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -129,50 +131,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static int GetModifierLength(Modifiers modifier)
{
switch (modifier)
{
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");
}
return GetModifierName(modifier).Length;
}
public static Modifiers GetModifierValue(string modifier)
@ -215,6 +174,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -215,6 +174,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return Modifiers.Async;
case "ref":
return Modifiers.Ref;
case "required":
return Modifiers.Required;
case "any":
// 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;

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

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

21
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -151,12 +151,13 @@ namespace ICSharpCode.Decompiler @@ -151,12 +151,13 @@ namespace ICSharpCode.Decompiler
{
parameterNullCheck = false;
lifetimeAnnotations = false;
requiredMembers = false;
}
}
public CSharp.LanguageVersion GetMinimumRequiredVersion()
{
if (parameterNullCheck || lifetimeAnnotations)
if (parameterNullCheck || lifetimeAnnotations || requiredMembers)
return CSharp.LanguageVersion.CSharp11_0;
if (fileScopedNamespaces || recordStructs)
return CSharp.LanguageVersion.CSharp10_0;
@ -356,6 +357,24 @@ namespace ICSharpCode.Decompiler @@ -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;
/// <summary>

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

@ -106,11 +106,14 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -106,11 +106,14 @@ namespace ICSharpCode.Decompiler.TypeSystem
// C# 9 attributes:
NativeInteger,
PreserveBaseOverrides,
// C# 11 attributes:
RequiredAttribute,
}
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]{
default,
@ -175,6 +178,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -175,6 +178,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
// C# 9 attributes:
new TopLevelTypeName("System.Runtime.CompilerServices", "NativeIntegerAttribute"),
new TopLevelTypeName("System.Runtime.CompilerServices", "PreserveBaseOverridesAttribute"),
// C# 11 attributes:
new TopLevelTypeName("System.Runtime.CompilerServices", "RequiredMemberAttribute"),
};
public static ref readonly TopLevelTypeName GetTypeName(this KnownAttribute attr)

9
ILSpy/Properties/Resources.Designer.cs generated

@ -1226,6 +1226,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -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>
/// Looks up a localized string similar to Separate local variable declarations and initializers (int x = 5; -&gt; int x; x = 5;), if possible.
/// </summary>

3
ILSpy/Properties/Resources.resx

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