diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index cef0c023a..8cbb8a1ff 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -191,7 +191,7 @@ namespace ICSharpCode.Decompiler.IL declaringType = new ParameterizedType(declaringType, declaringType.TypeParameters); } ILVariable ilVar = CreateILVariable(-1, declaringType, "this"); - ilVar.IsRefReadOnly = declaringType.GetDefinition()?.IsReadOnly == true; + ilVar.IsRefReadOnly = method.ThisIsRefReadOnly; parameterVariables[paramIndex++] = ilVar; } while (paramIndex < parameterVariables.Length) { diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs index c1a5de160..840c77e9b 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs @@ -272,8 +272,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms var type = method.DeclaringType; if (type.IsReferenceType == true) return false; // reference types are never implicitly copied - if (type.GetDefinition()?.IsReadOnly == true) - return false; // readonly structs are never implicitly copied + if (method.ThisIsRefReadOnly) + return false; // no copies for calls on readonly structs return true; } diff --git a/ICSharpCode.Decompiler/TypeSystem/IMethod.cs b/ICSharpCode.Decompiler/TypeSystem/IMethod.cs index c53d1cc60..1c98eb476 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/IMethod.cs @@ -40,6 +40,11 @@ namespace ICSharpCode.Decompiler.TypeSystem /// bool ReturnTypeIsRefReadOnly { get; } + /// + /// Gets whether the method is readonly (C# 8): accepts the 'this' reference as ref readonly + /// + bool ThisIsRefReadOnly { get; } + /// /// Gets the type parameters of this method; or an empty list if the method is not generic. /// diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs index 02d439f84..2a11babee 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs @@ -133,6 +133,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation IEnumerable IMethod.GetReturnTypeAttributes() => EmptyList.Instance; bool IMethod.ReturnTypeIsRefReadOnly => false; + bool IMethod.ThisIsRefReadOnly => false; public IReadOnlyList TypeParameters { get; set; } = EmptyList.Instance; diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs index 6a42b4364..cb53d51a6 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs @@ -117,6 +117,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation IEnumerable IEntity.GetAttributes() => baseMethod.GetAttributes(); IEnumerable IMethod.GetReturnTypeAttributes() => baseMethod.GetReturnTypeAttributes(); bool IMethod.ReturnTypeIsRefReadOnly => baseMethod.ReturnTypeIsRefReadOnly; + bool IMethod.ThisIsRefReadOnly => baseMethod.ThisIsRefReadOnly; /// /// We consider local functions as always static, because they do not have a "this parameter". /// Even local functions in instance methods capture this. diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs index d97382984..57e096823 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs @@ -426,6 +426,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } #endregion + public bool ThisIsRefReadOnly => DeclaringTypeDefinition?.IsReadOnly ?? false; + public Accessibility Accessibility => GetAccessibility(attributes); internal static Accessibility GetAccessibility(MethodAttributes attr) diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs index 311395fc4..c25ba6013 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs @@ -97,6 +97,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public IEnumerable GetReturnTypeAttributes() => methodDefinition.GetReturnTypeAttributes(); public bool ReturnTypeIsRefReadOnly => methodDefinition.ReturnTypeIsRefReadOnly; + bool IMethod.ThisIsRefReadOnly => methodDefinition.ThisIsRefReadOnly; + public IReadOnlyList TypeParameters { get { return specializedTypeParameters ?? methodDefinition.TypeParameters; diff --git a/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs b/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs index a151d1464..ecc0cbf22 100644 --- a/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs @@ -114,6 +114,7 @@ namespace ICSharpCode.Decompiler.TypeSystem IEnumerable IEntity.GetAttributes() => baseMethod.GetAttributes(); IEnumerable IMethod.GetReturnTypeAttributes() => baseMethod.GetReturnTypeAttributes(); bool IMethod.ReturnTypeIsRefReadOnly => baseMethod.ReturnTypeIsRefReadOnly; + bool IMethod.ThisIsRefReadOnly => baseMethod.ThisIsRefReadOnly; public IReadOnlyList TypeParameters { get { return baseMethod.TypeParameters; }