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. 9
      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
public struct NormalStruct public struct NormalStruct
{ {
private readonly int dummy; private readonly int dummy;
private int[] arr;
public int Property { public int Property {
get { get {
@ -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; public event EventHandler NormalEvent;
#if CS80
public readonly event EventHandler ReadOnlyEvent { public readonly event EventHandler ReadOnlyEvent {
add { add {
} }

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

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

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

@ -144,7 +144,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Name = Pattern.AnyString, Name = Pattern.AnyString,
PrivateImplementationType = new AnyNodeOrNull(), PrivateImplementationType = new AnyNodeOrNull(),
ReturnType = 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")) }
}
}; };
static readonly IndexerDeclaration CalculatedGetterOnlyIndexerPattern = new IndexerDeclaration() { static readonly IndexerDeclaration CalculatedGetterOnlyIndexerPattern = new IndexerDeclaration() {
@ -153,14 +156,25 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
PrivateImplementationType = new AnyNodeOrNull(), PrivateImplementationType = new AnyNodeOrNull(),
Parameters = { new Repeat(new AnyNode()) }, Parameters = { new Repeat(new AnyNode()) },
ReturnType = 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) void SimplifyPropertyDeclaration(PropertyDeclaration propertyDeclaration)
{ {
var m = CalculatedGetterOnlyPropertyPattern.Match(propertyDeclaration); var m = CalculatedGetterOnlyPropertyPattern.Match(propertyDeclaration);
if (!m.Success) if (!m.Success)
return; return;
if ((propertyDeclaration.Getter.Modifiers & ~movableModifiers) != 0)
return;
propertyDeclaration.Modifiers |= propertyDeclaration.Getter.Modifiers;
propertyDeclaration.ExpressionBody = m.Get<Expression>("expression").Single().Detach(); propertyDeclaration.ExpressionBody = m.Get<Expression>("expression").Single().Detach();
propertyDeclaration.Getter.Remove(); propertyDeclaration.Getter.Remove();
} }
@ -170,6 +184,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var m = CalculatedGetterOnlyIndexerPattern.Match(indexerDeclaration); var m = CalculatedGetterOnlyIndexerPattern.Match(indexerDeclaration);
if (!m.Success) if (!m.Success)
return; return;
if ((indexerDeclaration.Getter.Modifiers & ~movableModifiers) != 0)
return;
indexerDeclaration.Modifiers |= indexerDeclaration.Getter.Modifiers;
indexerDeclaration.ExpressionBody = m.Get<Expression>("expression").Single().Detach(); indexerDeclaration.ExpressionBody = m.Get<Expression>("expression").Single().Detach();
indexerDeclaration.Getter.Remove(); indexerDeclaration.Getter.Remove();
} }

9
ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

@ -228,7 +228,7 @@ namespace ICSharpCode.Decompiler.CSharp
} }
w.WriteElementString("WarningLevel", "4"); w.WriteElementString("WarningLevel", "4");
w.WriteElementString("AllowUnsafeBlocks", "True"); w.WriteElementString("AllowUnsafeBlocks", "True");
if (StrongNameKeyFile != null) { if (StrongNameKeyFile != null) {
w.WriteElementString("SignAssembly", "True"); w.WriteElementString("SignAssembly", "True");
w.WriteElementString("AssemblyOriginatorKeyFile", Path.GetFileName(StrongNameKeyFile)); w.WriteElementString("AssemblyOriginatorKeyFile", Path.GetFileName(StrongNameKeyFile));
@ -463,7 +463,7 @@ namespace ICSharpCode.Decompiler.CSharp
} catch (EndOfStreamException) { } catch (EndOfStreamException) {
// if the .resources can't be decoded, just save them as-is // if the .resources can't be decoded, just save them as-is
} }
} }
using (FileStream fs = new FileStream(Path.Combine(targetDirectory, fileName), FileMode.Create, FileAccess.Write)) { using (FileStream fs = new FileStream(Path.Combine(targetDirectory, fileName), FileMode.Create, FileAccess.Write)) {
entryStream.CopyTo(fs); entryStream.CopyTo(fs);
} }
@ -515,7 +515,10 @@ namespace ICSharpCode.Decompiler.CSharp
string name = b.ToString(); string name = b.ToString();
if (IsReservedFileSystemName(name)) if (IsReservedFileSystemName(name))
return name + "_"; return name + "_";
return name; else if (name == ".")
return "_";
else
return name;
} }
static bool IsReservedFileSystemName(string name) static bool IsReservedFileSystemName(string name)

5
ICSharpCode.Decompiler/TypeSystem/IProperty.cs

@ -30,5 +30,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
IMethod Setter { get; } IMethod Setter { get; }
bool IsIndexer { 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
/// Constraint on a type parameter. /// Constraint on a type parameter.
/// </summary> /// </summary>
Constraint, Constraint,
/// <summary>
/// Return type. Not actually an ISymbol implementation; but can appear as attribut target.
/// </summary>
ReturnType,
} }
/// <summary> /// <summary>

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

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

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

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

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

@ -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() private void DecodeSignature()
{ {
var propertyDef = module.metadata.GetPropertyDefinition(propertyHandle); var propertyDef = module.metadata.GetPropertyDefinition(propertyHandle);

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

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

Loading…
Cancel
Save