Browse Source

Add a special case to the `IsPrimaryConstructor` determination logic: for a `record struct` type, there must be at least one assignment from a constructor parameter to a `BackingFieldOfAutomaticProperty`.

pull/3598/head
sonyps5201314 2 months ago
parent
commit
1a0696e851
  1. 28
      ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs

28
ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs

@ -24,6 +24,7 @@ using System.Reflection;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -302,10 +303,11 @@ namespace ICSharpCode.Decompiler.CSharp
//判定主构造函数的唯一准则是: //判定主构造函数的唯一准则是:
//首先它不能是拷贝构造函数(已在外部排除),且能通过IsPrimaryConstructorFast的判定逻辑, //首先它不能是拷贝构造函数(已在外部排除),且能通过IsPrimaryConstructorFast的判定逻辑,
//然后这个构造函数中前面部分都是类成员属性/字段赋值语句, //然后这个构造函数中前面部分都是类成员属性/字段赋值语句,
//如果不是结构体的话,之后紧跟着是调用基类构造函数的语句即"base..ctor(...);", //如果不是结构体的话,之后紧跟着是调用基类构造函数的语句即`base..ctor(...);`,
//再之后紧跟着就是返回语句了,即"base..ctor(...);"之后不存在任何其他初始化语句。 //再之后紧跟着就是返回语句了,即`base..ctor(...);`之后不存在任何其他初始化语句。
//特殊情况:`record struct`类型时,必须至少存在一条从构造函数参数到`BackingFieldOfAutomaticProperty`的赋值语句。
//注意:不存在捕获参数的情况下,主构造函数的参数和类成员之间无任何对应关系! //注意:不存在捕获参数的情况下,主构造函数的参数和类成员之间无任何对应关系!
//注意:目前即使一个函数的原始代码形式是常规构造函数,但是如果它符合本IsPrimaryConstructor函数的判定规则也会将它翻译成主构造函数形式 //注意:目前即使一个函数的原始代码形式是常规构造函数,但是如果它符合本`IsPrimaryConstructor`函数的判定规则也会将它翻译成主构造函数形式
bool IsPrimaryConstructor(IMethod method, IMethod unspecializedMethod, Block body) bool IsPrimaryConstructor(IMethod method, IMethod unspecializedMethod, Block body)
{ {
Debug.Assert(method.IsConstructor); Debug.Assert(method.IsConstructor);
@ -331,6 +333,7 @@ namespace ICSharpCode.Decompiler.CSharp
return false; return false;
int cur_instruction_index = -1; int cur_instruction_index = -1;
bool foundAssignmentStatementFromConstructorParameterOfRecordStructToBackingFieldOfAutomaticProperty = false;
List<IMember> backingMembers = new List<IMember>(); List<IMember> backingMembers = new List<IMember>();
foreach (var instruction in body.Instructions) foreach (var instruction in body.Instructions)
{ {
@ -339,6 +342,16 @@ namespace ICSharpCode.Decompiler.CSharp
break; break;
if (!target.MatchLdThis()) if (!target.MatchLdThis())
return false; return false;
if (isStruct && recordTypeDef.IsRecord)
{
if (!foundAssignmentStatementFromConstructorParameterOfRecordStructToBackingFieldOfAutomaticProperty)
{
if (PatternStatementTransform.IsBackingFieldOfAutomaticProperty(field, out var _))
{
foundAssignmentStatementFromConstructorParameterOfRecordStructToBackingFieldOfAutomaticProperty = true;
}
}
}
IMember backingMember; IMember backingMember;
if (backingFieldToAutoProperty.TryGetValue(field, out var property)) if (backingFieldToAutoProperty.TryGetValue(field, out var property))
{ {
@ -352,6 +365,14 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
if (isStruct && recordTypeDef.IsRecord)
{
if (!foundAssignmentStatementFromConstructorParameterOfRecordStructToBackingFieldOfAutomaticProperty)
{
return false;
}
}
if (!isStruct) if (!isStruct)
{ {
if (cur_instruction_index != body.Instructions.Count - 2) if (cur_instruction_index != body.Instructions.Count - 2)
@ -1300,6 +1321,7 @@ namespace ICSharpCode.Decompiler.CSharp
bool? bodyHasLeadingOrTrailingNop = null; bool? bodyHasLeadingOrTrailingNop = null;
return DecompileBody(method, ref bodyHasLeadingOrTrailingNop); return DecompileBody(method, ref bodyHasLeadingOrTrailingNop);
} }
Block DecompileBody(IMethod method, ref bool? bodyHasLeadingOrTrailingNop) Block DecompileBody(IMethod method, ref bool? bodyHasLeadingOrTrailingNop)
{ {
if (method == null || method.MetadataToken.IsNil) if (method == null || method.MetadataToken.IsNil)

Loading…
Cancel
Save