Browse Source

`IsBaseCtorCall` no longer checks the number of parameters. Otherwise, it would cause the translation of the `DeserializationException` type in `https://github.com/restsharp/RestSharp/blob/dev/src/RestSharp/Serializers/DeseralizationException.cs` to fail, as it is a primary constructor declaration that calls a base constructor with two arguments.

Additionally, dotPeek's `IsPrimaryConstructorFast` function has been introduced. This is because, after the aforementioned modification to `IsBaseCtorCall`, the `NamedParameter` type in RestSharp was being incorrectly identified as a primary constructor. Without this correction, it would lead to many compilation errors.
pull/3598/head
sonyps5201314 2 months ago
parent
commit
828fb52390
  1. 57
      ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs

57
ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Threading; using System.Threading;
@ -159,6 +160,50 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
public static bool IsPrimaryConstructorFast(IMethod constructor, bool isStruct, bool recordPrimaryConstructor)
{
if (constructor.Parameters.Count == 0 && (isStruct || !recordPrimaryConstructor))
{
return false;
}
//下面注释的这一段就暂时不翻译了,因为目前在ILSpy中无法进行翻译,
//因为在ILSpy中RecordDecompiler.DetectPrimaryConstructor会先于TransformFieldAndConstructorInitializers执行,
//而在dotPeek中是先执行ExtractInstanceCtorInitializerTransformation再执行DetectPrimaryConstructorTransformation的
/*
IConstructorInitializer constructorInitializer = constructor.ConstructorInitializer;
if (constructorInitializer != null && constructorInitializer.Target is IThisReferenceExpression)
{
return false;
}
*/
if (!constructor.IsAbstract && constructor.DeclaringType.Kind != TypeKind.Interface && !constructor.HasBody)//IsExtern
{
return false;
}
if (constructor.DeclaringType.GetDefinition()?.IsAbstract ?? false)
{
var module = constructor.ParentModule as MetadataModule;
var handle = (MethodDefinitionHandle)constructor.MetadataToken;
var metadata = module.metadata;
var def = metadata.GetMethodDefinition(handle);
var attributes = def.Attributes;
if (!attributes.HasFlag(MethodAttributes.Family))//IsFamily
{
return false;
}
}
else if (!(constructor.Accessibility == Accessibility.Public))//IsPublic
{
return false;
}
if (constructor is VarArgInstanceMethod)
{
return false;
}
return true;
}
IMethod DetectPrimaryConstructor() IMethod DetectPrimaryConstructor()
{ {
if (recordTypeDef.IsRecord) if (recordTypeDef.IsRecord)
@ -190,11 +235,12 @@ namespace ICSharpCode.Decompiler.CSharp
return null; return null;
//判定主构造函数的唯一准则是: //判定主构造函数的唯一准则是:
//首先它不能是拷贝构造函数, //首先它不能是拷贝构造函数,且能通过IsPrimaryConstructorFast的判定逻辑,
//然后这个构造函数中前面部分都是类成员属性/字段赋值语句, //然后这个构造函数中前面部分都是类成员属性/字段赋值语句,
//之后是调用基类构造函数的语句即"base..ctor(...);", //之后是调用基类构造函数的语句即"base..ctor(...);",
//再之后就是返回语句了,即"base..ctor(...);"之后不存在任何其他初始化语句。 //再之后就是返回语句了,即"base..ctor(...);"之后不存在任何其他初始化语句。
//且主构造函数的参数和类成员之间无任何对应关系! //注意:不存在捕获参数的情况下,主构造函数的参数和类成员之间无任何对应关系!
//注意:目前即使一个函数的原始代码形式是常规构造函数,但是如果它符合本IsPrimaryConstructor函数的判定规则也会将它翻译成主构造函数形式
bool IsPrimaryConstructor(IMethod method, IMethod unspecializedMethod) bool IsPrimaryConstructor(IMethod method, IMethod unspecializedMethod)
{ {
Debug.Assert(method.IsConstructor); Debug.Assert(method.IsConstructor);
@ -202,6 +248,9 @@ namespace ICSharpCode.Decompiler.CSharp
if (IsCopyConstructor(method)) if (IsCopyConstructor(method))
return false; return false;
if (!IsPrimaryConstructorFast(method, isStruct, false))
return false;
var body = DecompileBody(method); var body = DecompileBody(method);
if (body == null) if (body == null)
return false; return false;
@ -435,7 +484,7 @@ namespace ICSharpCode.Decompiler.CSharp
return false; return false;
if (!object.Equals(baseCtorCall.Method.DeclaringType, baseClass)) if (!object.Equals(baseCtorCall.Method.DeclaringType, baseClass))
return false; return false;
if (baseCtorCall.Arguments.Count != (isInheritedRecord ? 2 : 1)) if (baseCtorCall.Arguments.Count <= 0)
return false; return false;
if (!baseCtorCall.Arguments[0].MatchLdThis()) if (!baseCtorCall.Arguments[0].MatchLdThis())
return false; return false;
@ -471,6 +520,8 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
return false; return false;
} }
if (baseCtorCall.Arguments.Count != (isInheritedRecord ? 2 : 1))
return false;
if (isInheritedRecord) if (isInheritedRecord)
{ {
if (!baseCtorCall.Arguments[1].MatchLdLoc(other)) if (!baseCtorCall.Arguments[1].MatchLdLoc(other))

Loading…
Cancel
Save