From a5505ab00dad578392acdc078e3e144ee24ab11a Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 16 Mar 2019 00:42:36 +0100 Subject: [PATCH] Expose IMethod.AccessorKind. This makes it easier to determine if a method is a setter, particular in generic classes where "m.AccessorOwner?.Setter == m" ended up being wrong. --- .../TestCases/Pretty/ValueTypes.cs | 20 +++++++++++++++++++ .../CSharp/Resolver/ReducedExtensionMethod.cs | 15 ++++---------- .../CSharp/StatementBuilder.cs | 2 +- .../IL/Transforms/AssignVariableNames.cs | 18 ++++++++++------- ICSharpCode.Decompiler/TypeSystem/IMethod.cs | 6 ++++++ .../TypeSystem/Implementation/FakeMember.cs | 2 ++ .../Implementation/MetadataMethod.cs | 3 ++- .../Implementation/SpecializedMethod.cs | 3 +++ .../TypeSystem/VarArgInstanceMethod.cs | 15 ++++++-------- 9 files changed, 55 insertions(+), 29 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs index 5042101d9..f3a827cc8 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs @@ -25,6 +25,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { public int Field; + public int Property { + get { + return Field; + } + set { + Field = value; + } + } + public S(int field) { Field = field; @@ -184,5 +193,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty Console.WriteLine("true"); } } + + public static void CallOnTemporary() + { + // Method can be called directly on temporaries + //InitObj2().MethodCalls(); + + // Setting a property requires a temporary to avoid + // CS1612 Cannot modify the return value of 'InitObj2()' because it is not a variable + S s = InitObj2(); + s.Property = 1; + } } } \ No newline at end of file diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs b/ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs index 0e08b1b63..ced22e011 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -172,17 +173,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver } } - public bool IsAccessor { - get { - return baseMethod.IsAccessor; - } - } - - public IMember AccessorOwner { - get { - return baseMethod.AccessorOwner; - } - } + public bool IsAccessor => baseMethod.IsAccessor; + public IMember AccessorOwner => baseMethod.AccessorOwner; + public MethodSemanticsAttributes AccessorKind => baseMethod.AccessorKind; public IMethod ReducedFrom { get { diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index a230461eb..f9527b162 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -763,7 +763,7 @@ namespace ICSharpCode.Decompiler.CSharp return false; switch (targetMethod.AccessorOwner) { case IProperty p: - return p.Setter == targetMethod; + return targetMethod.AccessorKind == System.Reflection.MethodSemanticsAttributes.Setter; default: return true; } diff --git a/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs b/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs index a3fdd2a13..9cdf8bcb4 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; using Humanizer; @@ -71,7 +72,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms var lastParameter = f.Method.Parameters.Last(); switch (f.Method.AccessorOwner) { case IProperty prop: - if (prop.Setter == f.Method) { + if (f.Method.AccessorKind == MethodSemanticsAttributes.Setter) { if (prop.Parameters.Any(p => p.Name == "value")) { f.Warnings.Add("Parameter named \"value\" already present in property signature!"); break; @@ -90,7 +91,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms } break; case IEvent ev: - if (f.Method != ev.InvokeAccessor) { + if (f.Method.AccessorKind != MethodSemanticsAttributes.Raiser) { var variableForLastParameter = f.Variables.FirstOrDefault(v => v.Function == f && v.Kind == VariableKind.Parameter && v.Index == f.Method.Parameters.Count - 1); @@ -124,11 +125,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms bool IsSetOrEventAccessor(IMethod method) { - if (method.AccessorOwner is IProperty p) - return p.Setter == method; - if (method.AccessorOwner is IEvent e) - return e.InvokeAccessor != method; - return false; + switch (method.AccessorKind) { + case MethodSemanticsAttributes.Setter: + case MethodSemanticsAttributes.Adder: + case MethodSemanticsAttributes.Remover: + return true; + default: + return false; + } } void PerformAssignment(ILFunction function) diff --git a/ICSharpCode.Decompiler/TypeSystem/IMethod.cs b/ICSharpCode.Decompiler/TypeSystem/IMethod.cs index c2161694b..24f550b5d 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/IMethod.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Reflection; namespace ICSharpCode.Decompiler.TypeSystem { @@ -69,6 +70,11 @@ namespace ICSharpCode.Decompiler.TypeSystem /// IMember AccessorOwner { get; } + /// + /// Gets the kind of accessor this is. + /// + MethodSemanticsAttributes AccessorKind { get; } + /// /// If this method is reduced from an extension method return the original method, null otherwise. /// A reduced method doesn't contain the extension method parameter. That means that has one parameter less than it's definition. diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs index b3303b2bc..54c8e6f26 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Reflection; using System.Reflection.Metadata; using ICSharpCode.Decompiler.Util; @@ -144,6 +145,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation bool IMethod.HasBody => false; bool IMethod.IsAccessor => false; IMember IMethod.AccessorOwner => null; + MethodSemanticsAttributes IMethod.AccessorKind => 0; IMethod IMethod.ReducedFrom => null; diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs index a7fec43e8..a3412cc4f 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs @@ -25,7 +25,6 @@ using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using ICSharpCode.Decompiler.Semantics; using ICSharpCode.Decompiler.Util; namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -40,6 +39,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation readonly SymbolKind symbolKind; readonly ITypeParameter[] typeParameters; readonly EntityHandle accessorOwner; + public MethodSemanticsAttributes AccessorKind { get; } public bool IsExtensionMethod { get; } // lazy-loaded fields: @@ -64,6 +64,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation if (semanticsAttribute != 0) { this.symbolKind = SymbolKind.Accessor; this.accessorOwner = accessorOwner; + this.AccessorKind = semanticsAttribute; } else if ((attributes & (MethodAttributes.SpecialName | MethodAttributes.RTSpecialName)) != 0) { string name = this.Name; if (name == ".cctor" || name == ".ctor") diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs index a5e7079c2..3decf1e0f 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using ICSharpCode.Decompiler.Util; @@ -125,6 +126,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation get { return methodDefinition.IsAccessor; } } + public MethodSemanticsAttributes AccessorKind => methodDefinition.AccessorKind; + public IMethod ReducedFrom { get { return null; } } diff --git a/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs b/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs index 01cc6bc12..dc12f9423 100644 --- a/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reflection; using System.Text; using ICSharpCode.Decompiler.TypeSystem.Implementation; @@ -142,14 +143,10 @@ namespace ICSharpCode.Decompiler.TypeSystem public bool HasBody { get { return baseMethod.HasBody; } } - - public bool IsAccessor { - get { return baseMethod.IsAccessor; } - } - - public IMember AccessorOwner { - get { return baseMethod.AccessorOwner; } - } + + public bool IsAccessor => baseMethod.IsAccessor; + public IMember AccessorOwner => baseMethod.AccessorOwner; + public MethodSemanticsAttributes AccessorKind => baseMethod.AccessorKind; public IMethod ReducedFrom { get { return baseMethod.ReducedFrom; } @@ -158,7 +155,7 @@ namespace ICSharpCode.Decompiler.TypeSystem #endregion #region IMember implementation - + IMember IMember.Specialize(TypeParameterSubstitution substitution) { return Specialize(substitution);