Browse Source

Fix #1943: "ref readonly" returns from properties/indexers

pull/1951/head
Daniel Grunwald 5 years ago
parent
commit
3bf9f7c301
  1. 10
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs
  2. 9
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  3. 21
      ICSharpCode.Decompiler/CSharp/Transforms/NormalizeBlockStatements.cs
  4. 3
      ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs
  5. 5
      ICSharpCode.Decompiler/TypeSystem/IProperty.cs
  6. 4
      ICSharpCode.Decompiler/TypeSystem/ISymbol.cs
  7. 4
      ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs
  8. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs
  9. 7
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataProperty.cs
  10. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedProperty.cs

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

@ -62,6 +62,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -62,6 +62,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public struct NormalStruct
{
private readonly int dummy;
private int[] arr;
public int Property {
get {
@ -96,8 +97,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -96,8 +97,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
public ref int RefProperty => ref arr[0];
public ref readonly int RefReadonlyProperty => ref arr[0];
public readonly ref int ReadonlyRefProperty => ref arr[0];
public readonly ref readonly int ReadonlyRefReadonlyProperty => ref arr[0];
#endif
public ref readonly int this[in int index] => ref arr[index];
public event EventHandler NormalEvent;
#if CS80
public readonly event EventHandler ReadOnlyEvent {
add {
}

9
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -1574,6 +1574,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1574,6 +1574,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
decl.AddAnnotation(new MemberResolveResult(null, property));
}
decl.ReturnType = ConvertType(property.ReturnType);
if (property.ReturnTypeIsRefReadOnly && decl.ReturnType is ComposedType ct && ct.HasRefSpecifier) {
ct.HasReadOnlySpecifier = true;
}
decl.Name = property.Name;
decl.Getter = ConvertAccessor(property.Getter, property.Accessibility, false);
decl.Setter = ConvertAccessor(property.Setter, property.Accessibility, true);
@ -1601,6 +1604,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1601,6 +1604,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
decl.AddAnnotation(new MemberResolveResult(null, indexer));
}
decl.ReturnType = ConvertType(indexer.ReturnType);
if (indexer.ReturnTypeIsRefReadOnly && decl.ReturnType is ComposedType ct && ct.HasRefSpecifier) {
ct.HasReadOnlySpecifier = true;
}
foreach (IParameter p in indexer.Parameters) {
decl.Parameters.Add(ConvertParameter(p));
}
@ -1695,6 +1701,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1695,6 +1701,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
decl.Modifiers = GetMemberModifiers(op);
decl.OperatorType = opType.Value;
decl.ReturnType = ConvertType(op.ReturnType);
if (op.ReturnTypeIsRefReadOnly && decl.ReturnType is ComposedType ct && ct.HasRefSpecifier) {
ct.HasReadOnlySpecifier = true;
}
foreach (IParameter p in op.Parameters) {
decl.Parameters.Add(ConvertParameter(p));
}

21
ICSharpCode.Decompiler/CSharp/Transforms/NormalizeBlockStatements.cs

@ -144,7 +144,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -144,7 +144,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Name = Pattern.AnyString,
PrivateImplementationType = new AnyNodeOrNull(),
ReturnType = new AnyNode(),
Getter = new Accessor() { Body = new BlockStatement() { new ReturnStatement(new AnyNode("expression")) } }
Getter = new Accessor() {
Modifiers = Modifiers.Any,
Body = new BlockStatement() { new ReturnStatement(new AnyNode("expression")) }
}
};
static readonly IndexerDeclaration CalculatedGetterOnlyIndexerPattern = new IndexerDeclaration() {
@ -153,14 +156,25 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -153,14 +156,25 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
PrivateImplementationType = new AnyNodeOrNull(),
Parameters = { new Repeat(new AnyNode()) },
ReturnType = new AnyNode(),
Getter = new Accessor() { Body = new BlockStatement() { new ReturnStatement(new AnyNode("expression")) } }
Getter = new Accessor() {
Modifiers = Modifiers.Any,
Body = new BlockStatement() { new ReturnStatement(new AnyNode("expression")) }
}
};
/// <summary>
/// Modifiers that are emitted on accessors, but can be moved to the property declaration.
/// </summary>
const Modifiers movableModifiers = Modifiers.Readonly;
void SimplifyPropertyDeclaration(PropertyDeclaration propertyDeclaration)
{
var m = CalculatedGetterOnlyPropertyPattern.Match(propertyDeclaration);
if (!m.Success)
return;
if ((propertyDeclaration.Getter.Modifiers & ~movableModifiers) != 0)
return;
propertyDeclaration.Modifiers |= propertyDeclaration.Getter.Modifiers;
propertyDeclaration.ExpressionBody = m.Get<Expression>("expression").Single().Detach();
propertyDeclaration.Getter.Remove();
}
@ -170,6 +184,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -170,6 +184,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var m = CalculatedGetterOnlyIndexerPattern.Match(indexerDeclaration);
if (!m.Success)
return;
if ((indexerDeclaration.Getter.Modifiers & ~movableModifiers) != 0)
return;
indexerDeclaration.Modifiers |= indexerDeclaration.Getter.Modifiers;
indexerDeclaration.ExpressionBody = m.Get<Expression>("expression").Single().Detach();
indexerDeclaration.Getter.Remove();
}

3
ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

@ -515,6 +515,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -515,6 +515,9 @@ namespace ICSharpCode.Decompiler.CSharp
string name = b.ToString();
if (IsReservedFileSystemName(name))
return name + "_";
else if (name == ".")
return "_";
else
return name;
}

5
ICSharpCode.Decompiler/TypeSystem/IProperty.cs

@ -30,5 +30,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -30,5 +30,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
IMethod Setter { get; }
bool IsIndexer { get; }
/// <summary>
/// Gets whether the return type is 'ref readonly'.
/// </summary>
bool ReturnTypeIsRefReadOnly { get; }
}
}

4
ICSharpCode.Decompiler/TypeSystem/ISymbol.cs

@ -73,6 +73,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -73,6 +73,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// Constraint on a type parameter.
/// </summary>
Constraint,
/// <summary>
/// Return type. Not actually an ISymbol implementation; but can appear as attribut target.
/// </summary>
ReturnType,
}
/// <summary>

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

@ -208,6 +208,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -208,6 +208,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
case SymbolKind.Method:
case SymbolKind.Accessor:
return (options & TypeSystemOptions.ReadOnlyMethods) != 0;
case SymbolKind.ReturnType:
case SymbolKind.Property:
case SymbolKind.Indexer:
return true; // "ref readonly" is currently always active
default:
return false;
}

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

@ -400,7 +400,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -400,7 +400,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
var retParam = metadata.GetParameter(parameters.First());
if (retParam.SequenceNumber == 0) {
b.AddMarshalInfo(retParam.GetMarshallingDescriptor());
b.Add(retParam.GetCustomAttributes(), symbolKind);
b.Add(retParam.GetCustomAttributes(), SymbolKind.ReturnType);
}
}
return b.Build();

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

@ -113,6 +113,13 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -113,6 +113,13 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
}
public bool ReturnTypeIsRefReadOnly {
get {
var propertyDef = module.metadata.GetPropertyDefinition(propertyHandle);
return propertyDef.GetCustomAttributes().HasKnownAttribute(module.metadata, KnownAttribute.IsReadOnly);
}
}
private void DecodeSignature()
{
var propertyDef = module.metadata.GetPropertyDefinition(propertyHandle);

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

@ -65,5 +65,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -65,5 +65,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public bool IsIndexer {
get { return propertyDefinition.IsIndexer; }
}
public bool ReturnTypeIsRefReadOnly => propertyDefinition.ReturnTypeIsRefReadOnly;
}
}

Loading…
Cancel
Save