Skip to content

Commit

Permalink
Improve XMLDoc lookup for explicit interface implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
ElektroKill committed Apr 2, 2024
1 parent 05b1c8a commit d164a7d
Showing 1 changed file with 62 additions and 21 deletions.
83 changes: 62 additions & 21 deletions dnSpy/dnSpy.Contracts.Logic/Decompiler/XmlDoc/XmlDocKeyProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using dnlib.DotNet;
Expand Down Expand Up @@ -59,10 +60,24 @@ public sealed class XmlDocKeyProvider {
b.Append("E:");
else if (member.IsMethod)
b.Append("M:");
AppendTypeName(b, member.DeclaringType);
b.Append('.');
if (member.DeclaringType is not null) {
AppendTypeName(b, member.DeclaringType);
b.Append('.');
}
if (IsExplicitInterfaceImplementation(member, out var declType)) {
AppendTypeName(b, declType, compiler, true);
b.Append('#');
}
var nameAsSystemString = UTF8String.ToSystemStringOrEmpty(member.Name);
b.Append(nameAsSystemString.Replace('.', '#'));
for (var i = 0; i < nameAsSystemString.Length; i++) {
char c = nameAsSystemString[i];
b.Append(c switch {
'.' => '#',
'<' => '{',
'>' => '}',
_ => c
});
}
IList<Parameter>? parameters;
TypeSig? explicitReturnType = null;
if (member.IsPropertyDef) {
Expand Down Expand Up @@ -102,6 +117,24 @@ public sealed class XmlDocKeyProvider {
return b;
}

static bool IsExplicitInterfaceImplementation(IMemberRef member, [NotNullWhen(true)] out TypeSig? type) {
type = null;
if (member.Name.IndexOf('.') >= 0)
return false;
var method = member switch {
MethodDef m => m,
PropertyDef p => p.GetMethod ?? p.SetMethod,
EventDef e => e.AddMethod ?? e.RemoveMethod ?? e.InvokeMethod,
_ => null
};
if (method is null)
return false;
if (method.Overrides.Count != 1)
return false;
type = method.Overrides[0].MethodDeclaration.DeclaringType.ToTypeSig();
return true;
}

static IEnumerable<Parameter> GetParameters(PropertyDef property) {
if (property.GetMethod is not null) {
foreach (var param in property.GetMethod.Parameters)
Expand All @@ -124,47 +157,53 @@ static IEnumerable<Parameter> GetParameters(PropertyDef property) {
}
}

static void AppendTypeName(StringBuilder b, TypeSig? type, XmlDocCompiler compiler) {
static void AppendTypeName(StringBuilder b, TypeSig? type, XmlDocCompiler compiler, bool explicitInterfaceImpl = false) {
if (type is null)
return;
// MSVC writes modifiers signatures and pinned to XML doc unlike other compilers.
if (compiler != XmlDocCompiler.MSVC)
type = type.RemovePinnedAndModifiers();
if (type is GenericInstSig giType) {
AppendTypeNameWithArguments(b, giType.GenericType?.TypeDefOrRef, giType.GenericArguments, compiler);
AppendTypeNameWithArguments(b, giType.GenericType?.TypeDefOrRef, giType.GenericArguments, compiler, explicitInterfaceImpl);
return;
}
if (type is ArraySigBase arrayType) {
AppendTypeName(b, arrayType.Next, compiler);
AppendTypeName(b, arrayType.Next, compiler, explicitInterfaceImpl);
b.Append('[');
var lowerBounds = arrayType.GetLowerBounds();
var sizes = arrayType.GetSizes();
for (int i = 0; i < arrayType.Rank; i++) {
if (i > 0)
b.Append(',');
if (i < lowerBounds.Count && i < sizes.Count) {
if (!explicitInterfaceImpl && i < lowerBounds.Count) {
b.Append(lowerBounds[i]);
b.Append(':');
b.Append(sizes[i] + lowerBounds[i] - 1);
if (i < sizes.Count)
b.Append(sizes[i] + lowerBounds[i] - 1);
}
}
b.Append(']');
return;
}
if (type is ByRefSig refType) {
AppendTypeName(b, refType.Next, compiler);
AppendTypeName(b, refType.Next, compiler, explicitInterfaceImpl);
b.Append('@');
return;
}
if (type is PtrSig ptrType) {
AppendTypeName(b, ptrType.Next, compiler);
AppendTypeName(b, ptrType.Next, compiler, explicitInterfaceImpl);
b.Append('*');
return;
}
if (type is GenericSig gp) {
b.Append('`');
if (explicitInterfaceImpl && gp.GenericParam?.Name is not null) {
b.Append(gp.GenericParam.Name);
return;
}
char c = explicitInterfaceImpl ? '!' : '`';
b.Append(c);
if (gp.IsMethodVar)
b.Append('`');
b.Append(c);
b.Append(gp.Number);
return;
}
Expand Down Expand Up @@ -207,32 +246,34 @@ static void AppendTypeName(StringBuilder b, TypeSig? type, XmlDocCompiler compil
return;
}

AppendTypeName(b, type.ToTypeDefOrRef());
AppendTypeName(b, type.ToTypeDefOrRef(), explicitInterfaceImpl);
}

static void AppendTypeName(StringBuilder b, ITypeDefOrRef typeDefOrRef) {
static void AppendTypeName(StringBuilder b, ITypeDefOrRef typeDefOrRef, bool explicitInterfaceImpl = false) {
if (typeDefOrRef.DeclaringType is not null) {
AppendTypeName(b, typeDefOrRef.DeclaringType);
b.Append('.');
b.Append(explicitInterfaceImpl ? '#' : '.');
b.Append(typeDefOrRef.Name);
}
else if (explicitInterfaceImpl)
b.Append(FullNameFactory.FullName(typeDefOrRef, false, null, null).Replace('.', '#'));
else
FullNameFactory.FullNameSB(typeDefOrRef, false, null, b);
}

static int AppendTypeNameWithArguments(StringBuilder b, ITypeDefOrRef? type, IList<TypeSig> genericArguments, XmlDocCompiler compiler) {
static int AppendTypeNameWithArguments(StringBuilder b, ITypeDefOrRef? type, IList<TypeSig> genericArguments, XmlDocCompiler compiler, bool explicitInterfaceImpl) {
if (type is null)
return 0;
int outerTypeParameterCount = 0;
if (type.DeclaringType is not null) {
outerTypeParameterCount = AppendTypeNameWithArguments(b, type.DeclaringType, genericArguments, compiler);
b.Append('.');
outerTypeParameterCount = AppendTypeNameWithArguments(b, type.DeclaringType, genericArguments, compiler, explicitInterfaceImpl);
b.Append(explicitInterfaceImpl ? '#' : '.');
}
else {
int len = b.Length;
FullNameFactory.NamespaceSB(type, true, b);
if (len != b.Length)
b.Append('.');
b.Append(explicitInterfaceImpl ? '#' : '.');
}
b.Append(SplitTypeParameterCountFromReflectionName(UTF8String.ToSystemStringOrEmpty(type.Name), out int localTypeParameterCount));

Expand All @@ -241,8 +282,8 @@ static int AppendTypeNameWithArguments(StringBuilder b, ITypeDefOrRef? type, ILi
b.Append('{');
for (int i = outerTypeParameterCount; i < totalTypeParameterCount && i < genericArguments.Count; i++) {
if (i > outerTypeParameterCount)
b.Append(',');
AppendTypeName(b, genericArguments[i], compiler);
b.Append(explicitInterfaceImpl ? '@' : ',');
AppendTypeName(b, genericArguments[i], compiler, explicitInterfaceImpl);
}
b.Append('}');
}
Expand Down

0 comments on commit d164a7d

Please sign in to comment.