Skip to content

Commit 7fa7ea5

Browse files
Fix #1682, fix #1949, fix #2394 and fix #3684: Added basic algorithm of IsAccessorInterfaceImplementationRuntimeHelper
1 parent 8af4d53 commit 7fa7ea5

4 files changed

Lines changed: 260 additions & 39 deletions

File tree

ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3684.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public static class CrossAssemblyProperties
88
public interface IInterface
99
{
1010
string Name { get; set; }
11+
T Convert<T>(T input);
1112
}
1213

1314
public class DerivedClass : BaseClass, IInterface

ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3684.dep.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ public string Name {
1212
name = value;
1313
}
1414
}
15+
16+
public T Convert<T>(T input) { return input; }
1517
}
1618
}

ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@ public static bool MemberIsHidden(MetadataFile module, EntityHandle member, Deco
292292
name = metadata.GetString(method.Name);
293293
if (name == ".ctor" && method.RelativeVirtualAddress == 0 && metadata.GetTypeDefinition(method.GetDeclaringType()).Attributes.HasFlag(System.Reflection.TypeAttributes.Import))
294294
return true;
295+
if (module is PEFile m && IsAccessorInterfaceImplementationRuntimeHelper(m, methodHandle))
296+
return true;
295297
if (settings.LocalFunctions && LocalFunctionDecompiler.IsLocalFunctionMethod(module, methodHandle))
296298
return true;
297299
if (settings.AnonymousMethods && methodHandle.HasGeneratedName(metadata) && methodHandle.IsCompilerGenerated(metadata))
@@ -386,6 +388,163 @@ static bool IsPrimaryConstructorParameterBackingField(SRM.FieldDefinition field,
386388
return name.StartsWith("<", StringComparison.Ordinal) && name.EndsWith(">P", StringComparison.Ordinal);
387389
}
388390

391+
static bool IsAccessorInterfaceImplementationRuntimeHelper(PEFile module, MethodDefinitionHandle handle)
392+
{
393+
var metadata = module.Metadata;
394+
var method = metadata.GetMethodDefinition(handle);
395+
if ((method.Attributes & System.Reflection.MethodAttributes.Static) != 0)
396+
return false;
397+
string rawName = metadata.GetString(method.Name);
398+
int dot = rawName.LastIndexOf('.');
399+
if (dot < 0)
400+
return false;
401+
string name = rawName.Substring(dot + 1);
402+
if (handle.GetMethodImplementations(metadata).Length == 0)
403+
return false;
404+
if (method.RelativeVirtualAddress == 0)
405+
return false;
406+
if (!name.StartsWith("get_", StringComparison.Ordinal) &&
407+
!name.StartsWith("set_", StringComparison.Ordinal) &&
408+
!name.StartsWith("add_", StringComparison.Ordinal) &&
409+
!name.StartsWith("remove_", StringComparison.Ordinal) &&
410+
!name.StartsWith("raise_", StringComparison.Ordinal))
411+
{
412+
return false;
413+
}
414+
415+
var signature = metadata.GetBlobReader(method.Signature);
416+
(int genericParameterCount, int parameterCount) = SignatureBlobComparer.ReadParameterCount(ref signature);
417+
if (genericParameterCount == -1 || parameterCount == -1)
418+
return false;
419+
signature.Reset();
420+
421+
int maximumMethodSize = 4 * (parameterCount + 1) + 5 + 1;
422+
423+
var body = module.Reader.GetMethodBody(method.RelativeVirtualAddress);
424+
var reader = body.GetILReader();
425+
426+
if (reader.RemainingBytes > maximumMethodSize)
427+
return false;
428+
429+
for (int i = 0; i < parameterCount + 1; i++)
430+
{
431+
int index;
432+
switch (reader.DecodeOpCode())
433+
{
434+
case ILOpCode.Ldarg:
435+
index = reader.ReadUInt16();
436+
if (index != i)
437+
return false;
438+
break;
439+
case ILOpCode.Ldarg_s:
440+
index = reader.ReadByte();
441+
if (index != i)
442+
return false;
443+
break;
444+
case ILOpCode.Ldarg_0:
445+
if (i != 0)
446+
return false;
447+
break;
448+
case ILOpCode.Ldarg_1:
449+
if (i != 1)
450+
return false;
451+
break;
452+
case ILOpCode.Ldarg_2:
453+
if (i != 2)
454+
return false;
455+
break;
456+
case ILOpCode.Ldarg_3:
457+
if (i != 3)
458+
return false;
459+
break;
460+
default:
461+
return false;
462+
}
463+
}
464+
465+
if (reader.DecodeOpCode() != ILOpCode.Call)
466+
return false;
467+
468+
EntityHandle targetHandle = MetadataTokenHelpers.EntityHandleOrNil(reader.ReadInt32());
469+
if (targetHandle.IsNil)
470+
return false;
471+
472+
if (reader.DecodeOpCode() != ILOpCode.Ret)
473+
return false;
474+
475+
if (reader.RemainingBytes != 0)
476+
return false;
477+
478+
BlobReader signature2;
479+
string otherName;
480+
481+
switch (targetHandle.Kind)
482+
{
483+
case HandleKind.MethodDefinition:
484+
if (genericParameterCount != 0)
485+
return false;
486+
var methodDef = metadata.GetMethodDefinition((MethodDefinitionHandle)targetHandle);
487+
signature2 = metadata.GetBlobReader(methodDef.Signature);
488+
otherName = metadata.GetString(methodDef.Name);
489+
break;
490+
case HandleKind.MethodSpecification:
491+
if (genericParameterCount == 0)
492+
return false;
493+
var methodSpec = metadata.GetMethodSpecification((MethodSpecificationHandle)targetHandle);
494+
var instantiationBlob = metadata.GetBlobReader(methodSpec.Signature);
495+
if (!IsIdentityInstantiation(ref instantiationBlob, genericParameterCount))
496+
return false;
497+
switch (methodSpec.Method.Kind)
498+
{
499+
case HandleKind.MethodDefinition:
500+
var methodSpecDef = metadata.GetMethodDefinition((MethodDefinitionHandle)methodSpec.Method);
501+
signature2 = metadata.GetBlobReader(methodSpecDef.Signature);
502+
otherName = metadata.GetString(methodSpecDef.Name);
503+
break;
504+
case HandleKind.MemberReference:
505+
var methodSpecRef = metadata.GetMemberReference((MemberReferenceHandle)methodSpec.Method);
506+
if (methodSpecRef.GetKind() != MemberReferenceKind.Method)
507+
return false;
508+
signature2 = metadata.GetBlobReader(methodSpecRef.Signature);
509+
otherName = metadata.GetString(methodSpecRef.Name);
510+
break;
511+
default:
512+
return false;
513+
}
514+
break;
515+
case HandleKind.MemberReference:
516+
var methodRef = metadata.GetMemberReference((MemberReferenceHandle)targetHandle);
517+
if (methodRef.GetKind() != MemberReferenceKind.Method)
518+
return false;
519+
signature2 = metadata.GetBlobReader(methodRef.Signature);
520+
otherName = metadata.GetString(methodRef.Name);
521+
break;
522+
default:
523+
return false;
524+
}
525+
526+
if (otherName != name)
527+
return false;
528+
return SignatureBlobComparer.EqualsMethodSignature(signature, signature2, metadata, metadata, skipModifiers: true);
529+
530+
static bool IsIdentityInstantiation(ref BlobReader reader, int expectedCount)
531+
{
532+
// Format: GENRICINST count type1 type2 ...
533+
if (reader.ReadByte() != 0x0A) // GENERICINST
534+
return false;
535+
if (!reader.TryReadCompressedInteger(out int count) || count != expectedCount)
536+
return false;
537+
for (int i = 0; i < count; i++)
538+
{
539+
if (reader.ReadByte() != 0x1E) // ELEMENT_TYPE_MVAR
540+
return false;
541+
if (!reader.TryReadCompressedInteger(out int index) || index != i)
542+
return false;
543+
}
544+
return true;
545+
}
546+
}
547+
389548
static bool IsSwitchOnStringCache(SRM.FieldDefinition field, MetadataReader metadata)
390549
{
391550
return metadata.GetString(field.Name).StartsWith("<>f__switch", StringComparison.Ordinal);

0 commit comments

Comments
 (0)