Browse Source

Implement basic support for generic methods in DecompilerTypeSystem + implement ResolveAsMember

pull/1198/head
Siegfried Pammer 7 years ago
parent
commit
22caec334b
  1. 227
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

227
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -141,7 +141,29 @@ namespace ICSharpCode.Decompiler.TypeSystem
public IMember ResolveAsMember(SRM.EntityHandle memberReference) public IMember ResolveAsMember(SRM.EntityHandle memberReference)
{ {
throw new NotImplementedException(); switch (memberReference.Kind) {
case SRM.HandleKind.FieldDefinition:
return ResolveAsField(memberReference);
case SRM.HandleKind.MethodDefinition:
return ResolveAsMethod(memberReference);
case SRM.HandleKind.MemberReference:
var mr = moduleDefinition.GetMetadataReader().GetMemberReference((SRM.MemberReferenceHandle)memberReference);
switch (mr.GetKind()) {
case SRM.MemberReferenceKind.Method:
return ResolveAsMethod(memberReference);
case SRM.MemberReferenceKind.Field:
return ResolveAsField(memberReference);
}
throw new NotSupportedException();
case SRM.HandleKind.EventDefinition:
return ResolveAsEvent(memberReference);
case SRM.HandleKind.PropertyDefinition:
return ResolveAsProperty(memberReference);
case SRM.HandleKind.MethodSpecification:
return ResolveAsMethod(memberReference);
default:
throw new NotSupportedException();
}
} }
#region Resolve Type #region Resolve Type
@ -262,62 +284,24 @@ namespace ICSharpCode.Decompiler.TypeSystem
ITypeDefinition declaringTypeDefinition; ITypeDefinition declaringTypeDefinition;
switch (methodReference.Kind) { switch (methodReference.Kind) {
case SRM.HandleKind.MethodDefinition: case SRM.HandleKind.MethodDefinition:
var methodDef = metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)methodReference);
declaringType = ResolveAsType(methodDef.GetDeclaringType());
declaringTypeDefinition = declaringType.GetDefinition();
if (declaringTypeDefinition == null) {
method = CreateFakeMethod(declaringType, metadata.GetString(methodDef.Name), methodDef.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default));
} else {
method = (IMethod)declaringTypeDefinition.GetMembers(m => m.MetadataToken == methodReference, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault()
?? CreateFakeMethod(declaringType, metadata.GetString(methodDef.Name), methodDef.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default));
}
break;
case SRM.HandleKind.MemberReference: case SRM.HandleKind.MemberReference:
var memberRef = metadata.GetMemberReference((SRM.MemberReferenceHandle)methodReference); method = FindNonGenericMethod(metadata, methodReference);
Debug.Assert(memberRef.GetKind() == SRM.MemberReferenceKind.Method);
declaringType = ResolveAsType(memberRef.Parent);
// TODO : Support other handles
declaringTypeDefinition = declaringType.GetDefinition();
var signature = memberRef.DecodeMethodSignature(TypeReferenceSignatureDecoder.Instance, default);
if (declaringTypeDefinition == null) {
method = CreateFakeMethod(declaringType, metadata.GetString(memberRef.Name), signature);
} else {
IEnumerable<IMethod> methods;
var name = metadata.GetString(memberRef.Name);
if (name == ".ctor") {
methods = declaringTypeDefinition.GetConstructors();
} else if (name == ".cctor") {
return declaringTypeDefinition.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic);
} else {
methods = declaringTypeDefinition.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers)
.Concat(declaringTypeDefinition.GetAccessors(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers));
}
IType[] parameterTypes;
if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) {
parameterTypes = signature.ParameterTypes
.Take(signature.RequiredParameterCount)
.Select(p => p.Resolve(context))
.Concat(new[] { SpecialType.ArgList })
.ToArray();
} else {
parameterTypes = signature.ParameterTypes.SelectArray(p => p.Resolve(context));
}
var returnType = signature.ReturnType.Resolve(context);
method = null;
foreach (var m in methods) {
if (m.TypeParameters.Count != signature.GenericParameterCount)
continue;
if (!CompareSignatures(m.Parameters, parameterTypes) || !CompareTypes(m.ReturnType, returnType))
continue;
method = m;
break;
}
if (method == null)
method = CreateFakeMethod(declaringType, metadata.GetString(memberRef.Name), signature);
}
break; break;
case SRM.HandleKind.MethodSpecification: case SRM.HandleKind.MethodSpecification:
throw new NotImplementedException(); var methodSpec = metadata.GetMethodSpecification((SRM.MethodSpecificationHandle)methodReference);
method = FindNonGenericMethod(metadata, methodSpec.Method);
IReadOnlyList<IType> classTypeArguments = null;
IReadOnlyList<IType> methodTypeArguments = null;
var typeArguments = methodSpec.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default);
if (typeArguments.Length > 0) {
methodTypeArguments = typeArguments.SelectArray(arg => arg.Resolve(context));
}
/*if (method.de) {
var git = (GenericInstanceType)methodReference.DeclaringType;
classTypeArguments = git.GenericArguments.SelectArray(Resolve);
}*/
method = method.Specialize(new TypeParameterSubstitution(classTypeArguments, methodTypeArguments));
break;
} }
/*method = FindNonGenericMethod(metadata, new Metadata.Entity(moduleDefinition, methodReference).ResolveAsMethod(), signature); /*method = FindNonGenericMethod(metadata, new Metadata.Entity(moduleDefinition, methodReference).ResolveAsMethod(), signature);
@ -332,20 +316,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
); );
break; break;
case SRM.HandleKind.MethodSpecification: case SRM.HandleKind.MethodSpecification:
IReadOnlyList<IType> classTypeArguments = null;
IReadOnlyList<IType> methodTypeArguments = null;
var methodSpec = metadata.GetMethodSpecification((SRM.MethodSpecificationHandle)methodReference);
var typeArguments = methodSpec.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default);
if (typeArguments.Length > 0) {
methodTypeArguments = typeArguments.SelectArray(arg => arg.Resolve(context));
}
var methodmethodSpec.Method.ResolveAsMethod(moduleDefinition);
if (methodReference.DeclaringType.IsGenericInstance) {
var git = (GenericInstanceType)methodReference.DeclaringType;
classTypeArguments = git.GenericArguments.SelectArray(Resolve);
}
method = method.Specialize(new TypeParameterSubstitution(classTypeArguments, methodTypeArguments));
break;
}*/ }*/
methodLookupCache.Add(methodReference, method); methodLookupCache.Add(methodReference, method);
@ -354,47 +325,73 @@ namespace ICSharpCode.Decompiler.TypeSystem
} }
} }
/*IMethod FindNonGenericMethod(SRM.MetadataReader metadata, Metadata.MethodDefinition method) IMethod FindNonGenericMethod(SRM.MetadataReader metadata, SRM.EntityHandle methodReference)
{ {
var methodDefinition = metadata.GetMethodDefinition(method.Handle); IType declaringType;
ITypeDefinition typeDef = ResolveAsType(methodDefinition.GetDeclaringType()).GetDefinition(); ITypeDefinition declaringTypeDefinition;
if (typeDef == null) string name;
return CreateFakeMethod(methodDefinition); switch (methodReference.Kind) {
IEnumerable<IMethod> methods; case SRM.HandleKind.MethodDefinition:
var name = metadata.GetString(methodDefinition.Name); var methodDef = metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)methodReference);
if (name == ".ctor") { declaringType = ResolveAsType(methodDef.GetDeclaringType());
methods = typeDef.GetConstructors(); declaringTypeDefinition = declaringType.GetDefinition();
} else if (name == ".cctor") { if (declaringTypeDefinition == null) {
return typeDef.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic); return CreateFakeMethod(declaringType, metadata.GetString(methodDef.Name), methodDef.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default));
} else { }
methods = typeDef.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers) name = metadata.GetString(methodDef.Name);
.Concat(typeDef.GetAccessors(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers)); IMethod method;
} if (name == ".ctor") {
foreach (var m in methods) { method = declaringTypeDefinition.GetConstructors(m => m.MetadataToken == methodReference, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
if (GetMetadata(m).AsMethod() == method) } else if (name == ".cctor") {
return m; method = declaringTypeDefinition.Methods.FirstOrDefault(m => m.MetadataToken == methodReference);
} } else {
IType[] parameterTypes; method = declaringTypeDefinition.GetMethods(m => m.MetadataToken == methodReference, GetMemberOptions.IgnoreInheritedMembers)
var signature = methodDefinition.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default); .Concat(declaringTypeDefinition.GetAccessors(m => m.MetadataToken == methodReference, GetMemberOptions.IgnoreInheritedMembers)).FirstOrDefault();
if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) { }
parameterTypes = signature.ParameterTypes return method ?? CreateFakeMethod(declaringType, metadata.GetString(methodDef.Name), methodDef.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default));
.Take(signature.RequiredParameterCount) case SRM.HandleKind.MemberReference:
.Select(p => p.Resolve(context)) var memberRef = metadata.GetMemberReference((SRM.MemberReferenceHandle)methodReference);
.Concat(new[] { SpecialType.ArgList }) Debug.Assert(memberRef.GetKind() == SRM.MemberReferenceKind.Method);
.ToArray(); declaringType = ResolveAsType(memberRef.Parent);
} else { // TODO : Support other handles
parameterTypes = signature.ParameterTypes.SelectArray(p => p.Resolve(context)); declaringTypeDefinition = declaringType.GetDefinition();
} var signature = memberRef.DecodeMethodSignature(TypeReferenceSignatureDecoder.Instance, default);
var returnType = signature.ReturnType.Resolve(context); if (declaringTypeDefinition == null) {
foreach (var m in methods) { return CreateFakeMethod(declaringType, metadata.GetString(memberRef.Name), signature);
if (m.TypeParameters.Count != signature.GenericParameterCount) }
continue; IEnumerable<IMethod> methods;
if (!CompareSignatures(m.Parameters, parameterTypes) || !CompareTypes(m.ReturnType, returnType)) name = metadata.GetString(memberRef.Name);
continue; if (name == ".ctor") {
return m; methods = declaringTypeDefinition.GetConstructors();
} else if (name == ".cctor") {
return declaringTypeDefinition.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic);
} else {
methods = declaringTypeDefinition.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers)
.Concat(declaringTypeDefinition.GetAccessors(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers));
}
IType[] parameterTypes;
if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) {
parameterTypes = signature.ParameterTypes
.Take(signature.RequiredParameterCount)
.Select(p => p.Resolve(context))
.Concat(new[] { SpecialType.ArgList })
.ToArray();
} else {
parameterTypes = signature.ParameterTypes.SelectArray(p => p.Resolve(context));
}
var returnType = signature.ReturnType.Resolve(context);
foreach (var m in methods) {
if (m.TypeParameters.Count != signature.GenericParameterCount)
continue;
if (!CompareSignatures(m.Parameters, parameterTypes) || !CompareTypes(m.ReturnType, returnType))
continue;
return m;
}
return CreateFakeMethod(declaringType, metadata.GetString(memberRef.Name), signature);
default:
throw new NotSupportedException();
} }
return CreateFakeMethod(methodDefinition); }
}*/
static bool CompareTypes(IType a, IType b) static bool CompareTypes(IType a, IType b)
{ {
@ -424,6 +421,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary> /// </summary>
IMethod CreateFakeMethod(IType declaringType, string name, SRM.MethodSignature<ITypeReference> signature) IMethod CreateFakeMethod(IType declaringType, string name, SRM.MethodSignature<ITypeReference> signature)
{ {
Debug.Assert(false, $"Creating fake method for {name}!");
var m = new DefaultUnresolvedMethod(); var m = new DefaultUnresolvedMethod();
if (name == ".ctor" || name == ".cctor") if (name == ".ctor" || name == ".cctor")
m.SymbolKind = SymbolKind.Constructor; m.SymbolKind = SymbolKind.Constructor;
@ -432,23 +430,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
m.ReturnType = signature.ReturnType; m.ReturnType = signature.ReturnType;
m.IsStatic = !signature.Header.IsInstance; m.IsStatic = !signature.Header.IsInstance;
/*ITypeReference declaringTypeReference; ITypeReference declaringTypeReference;
lock (typeReferenceCecilLoader) { lock (typeReferenceCecilLoader) {
var metadata = moduleDefinition.GetMetadataReader(); var metadata = moduleDefinition.GetMetadataReader();
declaringTypeReference = typeReferenceCecilLoader.ReadTypeReference(methodDefinition.GetDeclaringType());
string name = metadata.GetString(methodDefinition.Name);
var gps = methodDefinition.GetGenericParameters();
for (int i = 0; i < signature.GenericParameterCount; i++) { for (int i = 0; i < signature.GenericParameterCount; i++) {
var gp = metadata.GetGenericParameter(gps[i]); m.TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.Method, i, ""));
m.TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.Method, i, metadata.GetString(gp.Name)));
} }
var ps = methodDefinition.GetParameters(); for (int i = 0; i < signature.ParameterTypes.Length; i++) {
for (int i = 0; i < ps.Count; i++) { m.Parameters.Add(new DefaultUnresolvedParameter(signature.ParameterTypes[i], ""));
var p = metadata.GetParameter(ps.At(metadata, i));
m.Parameters.Add(new DefaultUnresolvedParameter(signature.ParameterTypes[i], metadata.GetString(p.Name)));
} }
} }
var type = declaringTypeReference.Resolve(context);*/
return new ResolvedFakeMethod(m, context.WithCurrentTypeDefinition(declaringType.GetDefinition()), declaringType); return new ResolvedFakeMethod(m, context.WithCurrentTypeDefinition(declaringType.GetDefinition()), declaringType);
} }

Loading…
Cancel
Save