Browse Source

Add metadata processing for C# 12 'ref readonly' parameters

pull/3239/head
Siegfried Pammer 10 months ago
parent
commit
02d2a8c1f8
  1. 2
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  2. 18
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs
  3. 1
      ICSharpCode.Decompiler/CSharp/CSharpLanguageVersion.cs
  4. 8
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  5. 6
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  6. 1
      ICSharpCode.Decompiler/CSharp/Transforms/EscapeInvalidIdentifiers.cs
  7. 24
      ICSharpCode.Decompiler/DecompilerSettings.cs
  8. 2
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  9. 3
      ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs
  10. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
  11. 8
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs
  12. 1
      ILSpy/Languages/CSharpLanguage.cs
  13. 18
      ILSpy/Properties/Resources.Designer.cs
  14. 3
      ILSpy/Properties/Resources.resx

2
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -596,7 +596,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -596,7 +596,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
CompilerOptions.UseRoslyn1_3_2 => CSharp.LanguageVersion.CSharp6,
CompilerOptions.UseRoslyn2_10_0 => CSharp.LanguageVersion.CSharp7_3,
CompilerOptions.UseRoslyn3_11_0 => CSharp.LanguageVersion.CSharp9_0,
_ => cscOptions.HasFlag(CompilerOptions.Preview) ? CSharp.LanguageVersion.Latest : CSharp.LanguageVersion.CSharp11_0,
_ => cscOptions.HasFlag(CompilerOptions.Preview) ? CSharp.LanguageVersion.Latest : CSharp.LanguageVersion.CSharp12_0,
};
DecompilerSettings settings = new(langVersion) {
// Never use file-scoped namespaces

18
ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs

@ -320,5 +320,23 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -320,5 +320,23 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
LastOrDefault() = 10000;
Console.WriteLine(ElementAtOrDefault(-5));
}
#if CS120
public ref readonly int M(in int x)
{
return ref x;
}
public ref readonly int M2(ref readonly int x)
{
return ref x;
}
public void Test()
{
int x = 32;
M(in x);
M2(in x);
}
#endif
}
}

1
ICSharpCode.Decompiler/CSharp/CSharpLanguageVersion.cs

@ -34,6 +34,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -34,6 +34,7 @@ namespace ICSharpCode.Decompiler.CSharp
CSharp9_0 = 900,
CSharp10_0 = 1000,
CSharp11_0 = 1100,
CSharp12_0 = 1200,
Preview = 1100,
Latest = 0x7FFFFFFF
}

8
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -4188,7 +4188,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -4188,7 +4188,13 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (!(input.Expression is DirectionExpression dirExpr && input.ResolveResult is ByReferenceResolveResult brrr))
return input;
dirExpr.FieldDirection = (FieldDirection)kind;
dirExpr.FieldDirection = kind switch {
ReferenceKind.Ref => FieldDirection.Ref,
ReferenceKind.Out => FieldDirection.Out,
ReferenceKind.In => FieldDirection.In,
ReferenceKind.RefReadOnly => FieldDirection.In,
_ => throw new NotSupportedException("Unsupported reference kind: " + kind)
};
dirExpr.RemoveAnnotations<ByReferenceResolveResult>();
if (brrr.ElementResult == null)
brrr = new ByReferenceResolveResult(brrr.ElementType, kind);

6
ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs

@ -205,7 +205,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -205,7 +205,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
foreach (var stmt in rootNode.DescendantsAndSelf.OfType<ExpressionStatement>())
{
if (!IsValidInStatementExpression(stmt.Expression))
if (stmt.Expression is DirectionExpression dir && IsValidInStatementExpression(dir.Expression))
{
stmt.Expression = dir.Expression.Detach();
}
else if (!IsValidInStatementExpression(stmt.Expression))
{
// fetch ILFunction
var function = stmt.Ancestors.SelectMany(a => a.Annotations.OfType<ILFunction>()).First(f => f.Parent == null);

1
ICSharpCode.Decompiler/CSharp/Transforms/EscapeInvalidIdentifiers.cs

@ -168,6 +168,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -168,6 +168,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
"System.Runtime.CompilerServices.NativeIntegerAttribute",
"System.Runtime.CompilerServices.RefSafetyRulesAttribute",
"System.Runtime.CompilerServices.ScopedRefAttribute",
"System.Runtime.CompilerServices.RequiresLocationAttribute",
"Microsoft.CodeAnalysis.EmbeddedAttribute",
};

24
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -159,10 +159,16 @@ namespace ICSharpCode.Decompiler @@ -159,10 +159,16 @@ namespace ICSharpCode.Decompiler
unsignedRightShift = false;
checkedOperators = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp12_0)
{
refReadOnlyParameters = false;
}
}
public CSharp.LanguageVersion GetMinimumRequiredVersion()
{
if (refReadOnlyParameters)
return CSharp.LanguageVersion.CSharp12_0;
if (scopedRef || requiredMembers || numericIntPtr || utf8StringLiterals || unsignedRightShift || checkedOperators)
return CSharp.LanguageVersion.CSharp11_0;
if (fileScopedNamespaces || recordStructs)
@ -1991,6 +1997,24 @@ namespace ICSharpCode.Decompiler @@ -1991,6 +1997,24 @@ namespace ICSharpCode.Decompiler
}
}
bool refReadOnlyParameters = true;
/// <summary>
/// Gets/sets whether RequiresLocationAttribute on parameters should be replaced with 'ref readonly' modifiers.
/// </summary>
[Category("C# 12.0 / VS 2022.8")]
[Description("DecompilerSettings.RefReadOnlyParameters")]
public bool RefReadOnlyParameters {
get { return refReadOnlyParameters; }
set {
if (refReadOnlyParameters != value)
{
refReadOnlyParameters = value;
OnPropertyChanged();
}
}
}
bool separateLocalVariableDeclarations = false;
/// <summary>

2
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -183,6 +183,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -183,6 +183,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
typeSystemOptions |= TypeSystemOptions.ScopedRef;
if (settings.NumericIntPtr)
typeSystemOptions |= TypeSystemOptions.NativeIntegersWithoutAttribute;
if (settings.RefReadOnlyParameters)
typeSystemOptions |= TypeSystemOptions.RefReadOnlyParameters;
return typeSystemOptions;
}

3
ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs

@ -255,6 +255,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -255,6 +255,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
case "ScopedRefAttribute":
return (options & TypeSystemOptions.ScopedRef) != 0
&& (target == SymbolKind.Parameter);
case "RequiresLocationAttribute":
return (options & TypeSystemOptions.RefReadOnlyParameters) != 0
&& (target == SymbolKind.Parameter);
default:
return false;
}

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

@ -95,6 +95,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -95,6 +95,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
CallerFilePath,
CallerLineNumber,
ScopedRef,
RequiresLocation,
// Type parameter attributes:
IsUnmanaged,
@ -173,6 +174,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -173,6 +174,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(CallerFilePathAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(CallerLineNumberAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", "ScopedRefAttribute"),
new TopLevelTypeName("System.Runtime.CompilerServices", "RequiresLocationAttribute"),
// Type parameter attributes:
new TopLevelTypeName("System.Runtime.CompilerServices", "IsUnmanagedAttribute"),
// Marshalling attributes:

8
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs

@ -105,6 +105,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -105,6 +105,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
if (parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.IsReadOnly))
return ReferenceKind.In;
}
if ((module.TypeSystemOptions & TypeSystemOptions.RefReadOnlyParameters) != 0
&& (attributes & inOut) == ParameterAttributes.In)
{
var metadata = module.metadata;
var parameterDef = metadata.GetParameter(handle);
if (parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.RequiresLocation))
return ReferenceKind.RefReadOnly;
}
return ReferenceKind.Ref;
}

1
ILSpy/Languages/CSharpLanguage.cs

@ -114,6 +114,7 @@ namespace ICSharpCode.ILSpy @@ -114,6 +114,7 @@ namespace ICSharpCode.ILSpy
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp9_0.ToString(), "C# 9.0 / VS 2019.8"),
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp10_0.ToString(), "C# 10.0 / VS 2022"),
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp11_0.ToString(), "C# 11.0 / VS 2022.4"),
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp12_0.ToString(), "C# 12.0 / VS 2022.8"),
};
}
return versions;

18
ILSpy/Properties/Resources.Designer.cs generated

@ -1154,15 +1154,6 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1154,15 +1154,6 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Use parameter null checking.
/// </summary>
public static string DecompilerSettings_ParameterNullCheck {
get {
return ResourceManager.GetString("DecompilerSettings.ParameterNullCheck", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Pattern combinators (and, or, not).
/// </summary>
@ -1235,6 +1226,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1235,6 +1226,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to &apos;ref readonly&apos; parameters.
/// </summary>
public static string DecompilerSettings_RefReadOnlyParameters {
get {
return ResourceManager.GetString("DecompilerSettings.RefReadOnlyParameters", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Relational patterns.
/// </summary>

3
ILSpy/Properties/Resources.resx

@ -432,6 +432,9 @@ Are you sure you want to continue?</value> @@ -432,6 +432,9 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.RecursivePatternMatching" xml:space="preserve">
<value>Recursive pattern matching</value>
</data>
<data name="DecompilerSettings.RefReadOnlyParameters" xml:space="preserve">
<value>'ref readonly' parameters</value>
</data>
<data name="DecompilerSettings.RelationalPatterns" xml:space="preserve">
<value>Relational patterns</value>
</data>

Loading…
Cancel
Save