Browse Source

Adds support for C# 9 covariant return types in methods and getter-only properties and indexers.

pull/2470/head
Siegfried Pammer 4 years ago
parent
commit
84704a7452
  1. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 50
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CovariantReturns.cs
  4. 23
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  5. 22
      ICSharpCode.Decompiler/DecompilerSettings.cs
  6. 4
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -107,6 +107,7 @@ @@ -107,6 +107,7 @@
<Compile Include="TestCases\Correctness\DeconstructionTests.cs" />
<Compile Include="TestCases\Correctness\DynamicTests.cs" />
<Compile Include="TestCases\Correctness\StringConcat.cs" />
<None Include="TestCases\Pretty\CovariantReturns.cs" />
<Compile Include="TestCases\VBPretty\VBPropertiesTest.cs" />
<None Include="TestCases\ILPretty\Issue2260SwitchString.cs" />
<None Include="TestCases\Pretty\Records.cs" />

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -573,6 +573,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -573,6 +573,12 @@ namespace ICSharpCode.Decompiler.Tests
RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview);
}
[Test]
public void CovariantReturns([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview);
}
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);

50
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CovariantReturns.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
namespace ICSharpCode.Decompiler.Tests.TestCases.CovariantReturns
{
public abstract class Base
{
public abstract Base Instance { get; }
public abstract Base this[int index] { get; }
public virtual Base Build()
{
throw null;
}
protected abstract Base SetParent(object parent);
}
public class Derived : Base
{
public override Derived Instance { get; }
public override Derived this[int index] {
get {
throw null;
}
}
public override Derived Build()
{
throw null;
}
protected override Derived SetParent(object parent)
{
throw null;
}
}
public class UseSites
{
public Base Test(Base x)
{
return x.Build();
}
public Derived Test(Derived x)
{
return x.Build();
}
}
}

23
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -1451,9 +1451,24 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1451,9 +1451,24 @@ namespace ICSharpCode.Decompiler.CSharp
{
SetNewModifier(methodDecl);
}
if (IsCovariantReturnOverride(method))
{
RemoveAttribute(methodDecl, KnownAttribute.PreserveBaseOverrides);
methodDecl.Modifiers &= ~(Modifiers.New | Modifiers.Virtual);
methodDecl.Modifiers |= Modifiers.Override;
}
return methodDecl;
}
private bool IsCovariantReturnOverride(IEntity entity)
{
if (!settings.CovariantReturns)
return false;
if (!entity.HasAttribute(KnownAttribute.PreserveBaseOverrides))
return false;
return true;
}
internal static bool IsWindowsFormsInitializeComponentMethod(IMethod method)
{
return method.ReturnType.Kind == TypeKind.Void && method.Name == "InitializeComponent" && method.DeclaringTypeDefinition.GetNonInterfaceBaseTypes().Any(t => t.FullName == "System.Windows.Forms.Control");
@ -1766,7 +1781,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1766,7 +1781,15 @@ namespace ICSharpCode.Decompiler.CSharp
var accessorHandle = (MethodDefinitionHandle)(property.Getter ?? property.Setter).MetadataToken;
var accessor = metadata.GetMethodDefinition(accessorHandle);
if (!accessorHandle.GetMethodImplementations(metadata).Any() && accessor.HasFlag(System.Reflection.MethodAttributes.Virtual) == accessor.HasFlag(System.Reflection.MethodAttributes.NewSlot))
{
SetNewModifier(propertyDecl);
}
if (IsCovariantReturnOverride(property.Getter))
{
RemoveAttribute(getter, KnownAttribute.PreserveBaseOverrides);
propertyDecl.Modifiers &= ~(Modifiers.New | Modifiers.Virtual);
propertyDecl.Modifiers |= Modifiers.Override;
}
return propertyDecl;
}
catch (Exception innerException) when (!(innerException is OperationCanceledException || innerException is DecompilerException))

22
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -139,12 +139,14 @@ namespace ICSharpCode.Decompiler @@ -139,12 +139,14 @@ namespace ICSharpCode.Decompiler
recordClasses = false;
withExpressions = false;
usePrimaryConstructorSyntax = false;
covariantReturns = false;
}
}
public CSharp.LanguageVersion GetMinimumRequiredVersion()
{
if (nativeIntegers || initAccessors || functionPointers || forEachWithGetEnumeratorExtension || recordClasses)
if (nativeIntegers || initAccessors || functionPointers || forEachWithGetEnumeratorExtension
|| recordClasses || withExpressions || usePrimaryConstructorSyntax || covariantReturns)
return CSharp.LanguageVersion.Preview;
if (nullableReferenceTypes || readOnlyMethods || asyncEnumerator || asyncUsingAndForEachStatement
|| staticLocalFunctions || ranges || switchExpressions)
@ -193,6 +195,24 @@ namespace ICSharpCode.Decompiler @@ -193,6 +195,24 @@ namespace ICSharpCode.Decompiler
}
}
bool covariantReturns = true;
/// <summary>
/// Decompile C# 9 covariant return types.
/// </summary>
[Category("C# 9.0 / VS 2019.8")]
[Description("DecompilerSettings.CovariantReturns")]
public bool CovariantReturns {
get { return covariantReturns; }
set {
if (covariantReturns != value)
{
covariantReturns = value;
OnPropertyChanged();
}
}
}
bool initAccessors = true;
/// <summary>

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

@ -102,11 +102,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -102,11 +102,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
// C# 9 attributes:
NativeInteger,
PreserveBaseOverrides,
}
static class KnownAttributes
{
internal const int Count = (int)KnownAttribute.NativeInteger + 1;
internal const int Count = (int)KnownAttribute.PreserveBaseOverrides + 1;
static readonly TopLevelTypeName[] typeNames = new TopLevelTypeName[Count]{
default,
@ -167,6 +168,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -167,6 +168,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
new TopLevelTypeName("System.Security.Permissions", "PermissionSetAttribute"),
// C# 9 attributes:
new TopLevelTypeName("System.Runtime.CompilerServices", "NativeIntegerAttribute"),
new TopLevelTypeName("System.Runtime.CompilerServices", "PreserveBaseOverridesAttribute"),
};
public static ref readonly TopLevelTypeName GetTypeName(this KnownAttribute attr)

Loading…
Cancel
Save