de4dot-cex/de4dot.code/renamer/asmmodules/TypeDef.cs

724 lines
23 KiB
C#
Raw Normal View History

2011-11-15 21:26:51 +08:00
/*
2015-10-30 05:45:26 +08:00
Copyright (C) 2011-2015 de4dot@gmail.com
2011-11-15 21:26:51 +08:00
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using dnlib.DotNet;
using de4dot.blocks;
2011-11-15 21:26:51 +08:00
namespace de4dot.code.renamer.asmmodules {
public class TypeInfo {
2012-11-22 16:14:51 +08:00
public ITypeDefOrRef typeRef;
public MTypeDef typeDef;
2012-11-22 16:14:51 +08:00
public TypeInfo(ITypeDefOrRef typeRef, MTypeDef typeDef) {
this.typeRef = typeRef;
2011-11-15 21:26:51 +08:00
this.typeDef = typeDef;
}
2012-11-03 03:10:34 +08:00
public TypeInfo(TypeInfo other, GenericInstSig git) {
2013-01-19 20:03:57 +08:00
this.typeRef = GenericArgsSubstitutor.Create(other.typeRef, git);
this.typeDef = other.typeDef;
}
public override int GetHashCode() {
return typeDef.GetHashCode() +
2012-11-22 16:14:51 +08:00
new SigComparer().GetHashCode(typeRef);
}
public override bool Equals(object obj) {
var other = obj as TypeInfo;
if (other == null)
return false;
return typeDef == other.typeDef &&
2012-11-22 16:14:51 +08:00
new SigComparer().Equals(typeRef, other.typeRef);
}
public override string ToString() {
2012-11-22 16:14:51 +08:00
return typeRef.ToString();
}
}
public class MethodDefKey {
public readonly MMethodDef methodDef;
public MethodDefKey(MMethodDef methodDef) {
this.methodDef = methodDef;
}
public override int GetHashCode() {
2012-11-03 03:10:34 +08:00
return MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(methodDef.MethodDef);
}
public override bool Equals(object obj) {
var other = obj as MethodDefKey;
if (other == null)
return false;
2012-11-03 03:10:34 +08:00
return MethodEqualityComparer.CompareDeclaringTypes.Equals(methodDef.MethodDef, other.methodDef.MethodDef);
}
}
public class MethodInst {
public MMethodDef origMethodDef;
2012-11-22 16:14:51 +08:00
public IMethodDefOrRef methodRef;
2012-11-22 16:14:51 +08:00
public MethodInst(MMethodDef origMethodDef, IMethodDefOrRef methodRef) {
this.origMethodDef = origMethodDef;
2012-11-22 16:14:51 +08:00
this.methodRef = methodRef;
}
public override string ToString() {
2012-11-22 16:14:51 +08:00
return methodRef.ToString();
}
}
public class MethodInstances {
2012-11-04 05:49:52 +08:00
Dictionary<IMethodDefOrRef, List<MethodInst>> methodInstances = new Dictionary<IMethodDefOrRef, List<MethodInst>>(MethodEqualityComparer.DontCompareDeclaringTypes);
2013-01-19 20:03:57 +08:00
public void InitializeFrom(MethodInstances other, GenericInstSig git) {
foreach (var list in other.methodInstances.Values) {
foreach (var methodInst in list) {
2013-01-19 20:03:57 +08:00
var newMethod = GenericArgsSubstitutor.Create(methodInst.methodRef, git);
Add(new MethodInst(methodInst.origMethodDef, newMethod));
}
}
}
2013-01-19 20:03:57 +08:00
public void Add(MethodInst methodInst) {
List<MethodInst> list;
2012-11-22 16:14:51 +08:00
var key = methodInst.methodRef;
2013-01-19 20:03:57 +08:00
if (methodInst.origMethodDef.IsNewSlot() || !methodInstances.TryGetValue(key, out list))
methodInstances[key] = list = new List<MethodInst>();
list.Add(methodInst);
}
2013-01-19 20:03:57 +08:00
public List<MethodInst> Lookup(IMethodDefOrRef methodRef) {
List<MethodInst> list;
2012-11-22 16:14:51 +08:00
methodInstances.TryGetValue(methodRef, out list);
return list;
}
2013-01-19 20:03:57 +08:00
public IEnumerable<List<MethodInst>> GetMethods() {
return methodInstances.Values;
}
}
// Keeps track of which methods of an interface that have been implemented
public class InterfaceMethodInfo {
TypeInfo iface;
Dictionary<MethodDefKey, MMethodDef> ifaceMethodToClassMethod = new Dictionary<MethodDefKey, MMethodDef>();
public TypeInfo IFace {
get { return iface; }
}
public Dictionary<MethodDefKey, MMethodDef> IfaceMethodToClassMethod {
get { return ifaceMethodToClassMethod; }
}
public InterfaceMethodInfo(TypeInfo iface) {
this.iface = iface;
2011-11-18 23:55:54 +08:00
foreach (var methodDef in iface.typeDef.AllMethods)
ifaceMethodToClassMethod[new MethodDefKey(methodDef)] = null;
}
public InterfaceMethodInfo(TypeInfo iface, InterfaceMethodInfo other) {
this.iface = iface;
foreach (var key in other.ifaceMethodToClassMethod.Keys)
ifaceMethodToClassMethod[key] = other.ifaceMethodToClassMethod[key];
}
2013-01-19 20:03:57 +08:00
public void Merge(InterfaceMethodInfo other) {
foreach (var key in other.ifaceMethodToClassMethod.Keys) {
if (other.ifaceMethodToClassMethod[key] == null)
continue;
if (ifaceMethodToClassMethod[key] != null)
throw new ApplicationException("Interface method already initialized");
ifaceMethodToClassMethod[key] = other.ifaceMethodToClassMethod[key];
}
}
// Returns the previous method, or null if none
2013-01-19 20:03:57 +08:00
public MMethodDef AddMethod(MMethodDef ifaceMethod, MMethodDef classMethod) {
var ifaceKey = new MethodDefKey(ifaceMethod);
if (!ifaceMethodToClassMethod.ContainsKey(ifaceKey))
throw new ApplicationException("Could not find interface method");
MMethodDef oldMethod;
ifaceMethodToClassMethod.TryGetValue(ifaceKey, out oldMethod);
ifaceMethodToClassMethod[ifaceKey] = classMethod;
return oldMethod;
}
2013-01-19 20:03:57 +08:00
public void AddMethodIfEmpty(MMethodDef ifaceMethod, MMethodDef classMethod) {
if (ifaceMethodToClassMethod[new MethodDefKey(ifaceMethod)] == null)
2013-01-19 20:03:57 +08:00
AddMethod(ifaceMethod, classMethod);
}
public override string ToString() {
return iface.ToString();
}
}
public class InterfaceMethodInfos {
2012-11-03 03:10:34 +08:00
Dictionary<ITypeDefOrRef, InterfaceMethodInfo> interfaceMethods = new Dictionary<ITypeDefOrRef, InterfaceMethodInfo>(TypeEqualityComparer.Instance);
public IEnumerable<InterfaceMethodInfo> AllInfos {
get { return interfaceMethods.Values; }
}
2013-01-19 20:03:57 +08:00
public void InitializeFrom(InterfaceMethodInfos other, GenericInstSig git) {
foreach (var pair in other.interfaceMethods) {
var oldTypeInfo = pair.Value.IFace;
var newTypeInfo = new TypeInfo(oldTypeInfo, git);
2012-11-22 16:14:51 +08:00
var oldKey = oldTypeInfo.typeRef;
var newKey = newTypeInfo.typeRef;
InterfaceMethodInfo newMethodsInfo = new InterfaceMethodInfo(newTypeInfo, other.interfaceMethods[oldKey]);
if (interfaceMethods.ContainsKey(newKey))
2013-01-19 20:03:57 +08:00
newMethodsInfo.Merge(interfaceMethods[newKey]);
interfaceMethods[newKey] = newMethodsInfo;
}
}
2013-01-19 20:03:57 +08:00
public void AddInterface(TypeInfo iface) {
2012-11-22 16:14:51 +08:00
var key = iface.typeRef;
if (!interfaceMethods.ContainsKey(key))
interfaceMethods[key] = new InterfaceMethodInfo(iface);
}
// Returns the previous classMethod, or null if none
2013-01-19 20:03:57 +08:00
public MMethodDef AddMethod(TypeInfo iface, MMethodDef ifaceMethod, MMethodDef classMethod) {
return AddMethod(iface.typeRef, ifaceMethod, classMethod);
}
// Returns the previous classMethod, or null if none
2013-01-19 20:03:57 +08:00
public MMethodDef AddMethod(ITypeDefOrRef iface, MMethodDef ifaceMethod, MMethodDef classMethod) {
InterfaceMethodInfo info;
2012-11-03 03:10:34 +08:00
if (!interfaceMethods.TryGetValue(iface, out info))
throw new ApplicationException("Could not find interface");
2013-01-19 20:03:57 +08:00
return info.AddMethod(ifaceMethod, classMethod);
}
2013-01-19 20:03:57 +08:00
public void AddMethodIfEmpty(TypeInfo iface, MMethodDef ifaceMethod, MMethodDef classMethod) {
InterfaceMethodInfo info;
2012-11-22 16:14:51 +08:00
if (!interfaceMethods.TryGetValue(iface.typeRef, out info))
throw new ApplicationException("Could not find interface");
2013-01-19 20:03:57 +08:00
info.AddMethodIfEmpty(ifaceMethod, classMethod);
}
2011-11-15 21:26:51 +08:00
}
public class MTypeDef : Ref {
2011-11-15 21:26:51 +08:00
EventDefDict events = new EventDefDict();
FieldDefDict fields = new FieldDefDict();
MethodDefDict methods = new MethodDefDict();
PropertyDefDict properties = new PropertyDefDict();
TypeDefDict types = new TypeDefDict();
List<MGenericParamDef> genericParams;
2011-11-15 21:26:51 +08:00
internal TypeInfo baseType = null;
internal IList<TypeInfo> interfaces = new List<TypeInfo>(); // directly implemented interfaces
internal IList<MTypeDef> derivedTypes = new List<MTypeDef>();
2011-11-15 21:26:51 +08:00
Module module;
bool initializeVirtualMembersCalled = false;
MethodInstances virtualMethodInstances = new MethodInstances();
Dictionary<TypeInfo, bool> allImplementedInterfaces = new Dictionary<TypeInfo, bool>();
InterfaceMethodInfos interfaceMethodInfos = new InterfaceMethodInfos();
2011-11-17 11:17:03 +08:00
public Module Module {
get { return module; }
}
2011-11-21 17:36:23 +08:00
// Returns false if this is a type from a dependency (non-renamble) assembly (eg. mscorlib)
2011-11-15 21:26:51 +08:00
public bool HasModule {
get { return module != null; }
}
public IList<MGenericParamDef> GenericParams {
2011-11-17 11:17:03 +08:00
get { return genericParams; }
}
public IEnumerable<MTypeDef> NestedTypes {
2013-01-19 20:03:57 +08:00
get { return types.GetSorted(); }
2011-11-15 21:26:51 +08:00
}
public MTypeDef NestingType { get; set; }
2011-11-15 21:26:51 +08:00
public TypeDef TypeDef {
2012-11-22 16:14:51 +08:00
get { return (TypeDef)memberRef; }
2011-11-15 21:26:51 +08:00
}
public IEnumerable<MEventDef> AllEvents {
2013-01-19 20:03:57 +08:00
get { return events.GetValues(); }
2011-11-18 23:55:54 +08:00
}
public IEnumerable<MFieldDef> AllFields {
2013-01-19 20:03:57 +08:00
get { return fields.GetValues(); }
2011-11-18 23:55:54 +08:00
}
public IEnumerable<MMethodDef> AllMethods {
2013-01-19 20:03:57 +08:00
get { return methods.GetValues(); }
2011-11-18 23:55:54 +08:00
}
public IEnumerable<MPropertyDef> AllProperties {
2013-01-19 20:03:57 +08:00
get { return properties.GetValues(); }
2011-11-18 23:55:54 +08:00
}
public IEnumerable<MEventDef> AllEventsSorted {
2013-01-19 20:03:57 +08:00
get { return events.GetSorted(); }
2011-11-18 23:55:54 +08:00
}
public IEnumerable<MFieldDef> AllFieldsSorted {
2013-01-19 20:03:57 +08:00
get { return fields.GetSorted(); }
2011-11-18 23:55:54 +08:00
}
public IEnumerable<MMethodDef> AllMethodsSorted {
2013-01-19 20:03:57 +08:00
get { return methods.GetSorted(); }
2011-11-18 23:55:54 +08:00
}
public IEnumerable<MPropertyDef> AllPropertiesSorted {
2013-01-19 20:03:57 +08:00
get { return properties.GetSorted(); }
2011-11-18 23:55:54 +08:00
}
2012-11-22 16:14:51 +08:00
public MTypeDef(TypeDef typeDef, Module module, int index)
: base(typeDef, null, index) {
2011-11-15 21:26:51 +08:00
this.module = module;
2013-01-19 20:03:57 +08:00
genericParams = MGenericParamDef.CreateGenericParamDefList(TypeDef.GenericParameters);
2011-11-15 21:26:51 +08:00
}
2013-01-19 20:03:57 +08:00
public void AddInterface(MTypeDef ifaceDef, ITypeDefOrRef iface) {
2011-11-15 21:26:51 +08:00
if (ifaceDef == null || iface == null)
return;
interfaces.Add(new TypeInfo(iface, ifaceDef));
}
2013-01-19 20:03:57 +08:00
public void AddBaseType(MTypeDef baseDef, ITypeDefOrRef baseRef) {
2011-11-15 21:26:51 +08:00
if (baseDef == null || baseRef == null)
return;
baseType = new TypeInfo(baseRef, baseDef);
}
2013-01-19 20:03:57 +08:00
public void Add(MEventDef e) {
events.Add(e);
2011-11-15 21:26:51 +08:00
}
2013-01-19 20:03:57 +08:00
public void Add(MFieldDef f) {
fields.Add(f);
2011-11-15 21:26:51 +08:00
}
2013-01-19 20:03:57 +08:00
public void Add(MMethodDef m) {
methods.Add(m);
2011-11-15 21:26:51 +08:00
}
2013-01-19 20:03:57 +08:00
public void Add(MPropertyDef p) {
properties.Add(p);
2011-11-15 21:26:51 +08:00
}
2013-01-19 20:03:57 +08:00
public void Add(MTypeDef t) {
types.Add(t);
2011-11-15 21:26:51 +08:00
}
2013-01-19 20:03:57 +08:00
public MMethodDef FindMethod(MemberRef mr) {
return methods.Find(mr);
2011-11-15 21:26:51 +08:00
}
2013-01-19 20:03:57 +08:00
public MMethodDef FindMethod(IMethodDefOrRef md) {
return methods.Find(md);
2012-11-04 07:50:24 +08:00
}
2013-01-19 20:03:57 +08:00
public MMethodDef FindMethod(MethodDef md) {
return methods.Find(md);
2012-11-03 03:10:34 +08:00
}
2013-01-19 20:03:57 +08:00
public MMethodDef FindAnyMethod(MemberRef mr) {
return methods.FindAny(mr);
2011-12-28 20:24:02 +08:00
}
2013-01-19 20:03:57 +08:00
public MFieldDef FindField(MemberRef fr) {
return fields.Find(fr);
2011-11-15 21:26:51 +08:00
}
2013-01-19 20:03:57 +08:00
public MFieldDef FindAnyField(MemberRef fr) {
return fields.FindAny(fr);
2011-12-28 20:24:02 +08:00
}
2013-01-19 20:03:57 +08:00
public MPropertyDef Find(PropertyDef pr) {
return properties.Find(pr);
2011-11-21 17:36:23 +08:00
}
2013-01-19 20:03:57 +08:00
public MPropertyDef FindAny(PropertyDef pr) {
return properties.FindAny(pr);
2011-12-28 20:24:02 +08:00
}
2013-01-19 20:03:57 +08:00
public MEventDef Find(EventDef er) {
return events.Find(er);
2011-11-23 13:41:28 +08:00
}
2013-01-19 20:03:57 +08:00
public MEventDef FindAny(EventDef er) {
return events.FindAny(er);
2011-12-28 20:24:02 +08:00
}
2013-01-19 20:03:57 +08:00
public MPropertyDef Create(PropertyDef newProp) {
if (FindAny(newProp) != null)
2011-11-21 17:36:23 +08:00
throw new ApplicationException("Can't add a property when it's already been added");
var propDef = new MPropertyDef(newProp, this, properties.Count);
2013-01-19 20:03:57 +08:00
Add(propDef);
TypeDef.Properties.Add(newProp);
2011-11-21 17:36:23 +08:00
return propDef;
}
2013-01-19 20:03:57 +08:00
public MEventDef Create(EventDef newEvent) {
if (FindAny(newEvent) != null)
2011-11-23 13:41:28 +08:00
throw new ApplicationException("Can't add an event when it's already been added");
var eventDef = new MEventDef(newEvent, this, events.Count);
2013-01-19 20:03:57 +08:00
Add(eventDef);
TypeDef.Events.Add(newEvent);
2011-11-23 13:41:28 +08:00
return eventDef;
}
2013-01-19 20:03:57 +08:00
public void AddMembers() {
var type = TypeDef;
2011-11-15 21:26:51 +08:00
for (int i = 0; i < type.Events.Count; i++)
2013-01-19 20:03:57 +08:00
Add(new MEventDef(type.Events[i], this, i));
2011-11-15 21:26:51 +08:00
for (int i = 0; i < type.Fields.Count; i++)
2013-01-19 20:03:57 +08:00
Add(new MFieldDef(type.Fields[i], this, i));
2011-11-15 21:26:51 +08:00
for (int i = 0; i < type.Methods.Count; i++)
2013-01-19 20:03:57 +08:00
Add(new MMethodDef(type.Methods[i], this, i));
2011-11-15 21:26:51 +08:00
for (int i = 0; i < type.Properties.Count; i++)
2013-01-19 20:03:57 +08:00
Add(new MPropertyDef(type.Properties[i], this, i));
2011-11-18 23:55:54 +08:00
2013-01-19 20:03:57 +08:00
foreach (var propDef in properties.GetValues()) {
foreach (var method in propDef.MethodDefs()) {
var methodDef = FindMethod(method);
2011-11-18 23:55:54 +08:00
if (methodDef == null)
throw new ApplicationException("Could not find property method");
methodDef.Property = propDef;
if (method == propDef.PropertyDef.GetMethod)
2011-11-21 17:36:23 +08:00
propDef.GetMethod = methodDef;
if (method == propDef.PropertyDef.SetMethod)
2011-11-21 17:36:23 +08:00
propDef.SetMethod = methodDef;
2011-11-18 23:55:54 +08:00
}
}
2013-01-19 20:03:57 +08:00
foreach (var eventDef in events.GetValues()) {
foreach (var method in eventDef.MethodDefs()) {
var methodDef = FindMethod(method);
2011-11-18 23:55:54 +08:00
if (methodDef == null)
throw new ApplicationException("Could not find event method");
methodDef.Event = eventDef;
if (method == eventDef.EventDef.AddMethod)
2011-11-21 17:36:23 +08:00
eventDef.AddMethod = methodDef;
if (method == eventDef.EventDef.RemoveMethod)
2011-11-21 17:36:23 +08:00
eventDef.RemoveMethod = methodDef;
if (method == eventDef.EventDef.InvokeMethod)
2011-11-21 17:36:23 +08:00
eventDef.RaiseMethod = methodDef;
2011-11-18 23:55:54 +08:00
}
}
}
2013-01-19 20:03:57 +08:00
public void OnTypesRenamed() {
events.OnTypesRenamed();
properties.OnTypesRenamed();
fields.OnTypesRenamed();
methods.OnTypesRenamed();
types.OnTypesRenamed();
2011-11-15 21:26:51 +08:00
}
2013-01-19 20:03:57 +08:00
public bool IsNested() {
2011-11-17 11:17:03 +08:00
return NestingType != null;
}
2013-01-19 20:03:57 +08:00
public bool IsGlobalType() {
if (!IsNested())
return TypeDef.IsPublic;
2012-11-03 03:10:34 +08:00
switch (TypeDef.Visibility) {
2011-11-17 11:17:03 +08:00
case TypeAttributes.NestedPrivate:
case TypeAttributes.NestedAssembly:
case TypeAttributes.NestedFamANDAssem:
return false;
case TypeAttributes.NestedPublic:
case TypeAttributes.NestedFamily:
case TypeAttributes.NestedFamORAssem:
2013-01-19 20:03:57 +08:00
return NestingType.IsGlobalType();
2011-11-17 11:17:03 +08:00
default:
return false;
}
}
2013-01-19 20:03:57 +08:00
public void InitializeVirtualMembers(MethodNameGroups groups, IResolver resolver) {
if (initializeVirtualMembersCalled)
return;
initializeVirtualMembersCalled = true;
foreach (var iface in interfaces)
2013-01-19 20:03:57 +08:00
iface.typeDef.InitializeVirtualMembers(groups, resolver);
if (baseType != null)
2013-01-19 20:03:57 +08:00
baseType.typeDef.InitializeVirtualMembers(groups, resolver);
2013-01-19 20:03:57 +08:00
foreach (var methodDef in methods.GetValues()) {
if (methodDef.IsVirtual())
groups.Add(methodDef);
}
2013-01-19 20:03:57 +08:00
InstantiateVirtualMembers(groups);
InitializeInterfaceMethods(groups);
}
2013-01-19 20:03:57 +08:00
void InitializeAllInterfaces() {
if (baseType != null)
2013-01-19 20:03:57 +08:00
InitializeInterfaces(baseType);
foreach (var iface in interfaces) {
allImplementedInterfaces[iface] = true;
2013-01-19 20:03:57 +08:00
interfaceMethodInfos.AddInterface(iface);
InitializeInterfaces(iface);
}
}
2013-01-19 20:03:57 +08:00
void InitializeInterfaces(TypeInfo typeInfo) {
2012-12-20 01:14:47 +08:00
var git = typeInfo.typeRef.TryGetGenericInstSig();
2013-01-19 20:03:57 +08:00
interfaceMethodInfos.InitializeFrom(typeInfo.typeDef.interfaceMethodInfos, git);
foreach (var info in typeInfo.typeDef.allImplementedInterfaces.Keys) {
var newTypeInfo = new TypeInfo(info, git);
allImplementedInterfaces[newTypeInfo] = true;
}
}
2013-01-19 20:03:57 +08:00
void InitializeInterfaceMethods(MethodNameGroups groups) {
InitializeAllInterfaces();
if (TypeDef.IsInterface)
return;
//--- Partition II 12.2 Implementing virtual methods on interfaces:
//--- The VES shall use the following algorithm to determine the appropriate
//--- implementation of an interface's virtual abstract methods:
//---
//--- * If the base class implements the interface, start with the same virtual methods
//--- that it provides; otherwise, create an interface that has empty slots for all
//--- virtual functions.
// Done. See initializeAllInterfaces().
2012-11-04 05:49:52 +08:00
var methodsDict = new Dictionary<IMethodDefOrRef, MMethodDef>(MethodEqualityComparer.DontCompareDeclaringTypes);
//--- * If this class explicitly specifies that it implements the interface (i.e., the
//--- interfaces that appear in this class InterfaceImpl table, §22.23)
//--- * If the class defines any public virtual newslot methods whose name and
//--- signature match a virtual method on the interface, then use these new virtual
//--- methods to implement the corresponding interface method.
if (interfaces.Count > 0) {
methodsDict.Clear();
2013-01-19 20:03:57 +08:00
foreach (var method in methods.GetValues()) {
if (!method.IsPublic() || !method.IsVirtual() || !method.IsNewSlot())
continue;
2012-11-03 05:53:24 +08:00
methodsDict[method.MethodDef] = method;
}
foreach (var ifaceInfo in interfaces) {
2013-01-19 20:03:57 +08:00
foreach (var methodsList in ifaceInfo.typeDef.virtualMethodInstances.GetMethods()) {
if (methodsList.Count < 1)
continue;
var methodInst = methodsList[0];
var ifaceMethod = methodInst.origMethodDef;
2013-01-19 20:03:57 +08:00
if (!ifaceMethod.IsVirtual())
continue;
2013-01-19 20:03:57 +08:00
var ifaceMethodRef = GenericArgsSubstitutor.Create(methodInst.methodRef, ifaceInfo.typeRef.TryGetGenericInstSig());
MMethodDef classMethod;
2012-11-22 16:14:51 +08:00
if (!methodsDict.TryGetValue(ifaceMethodRef, out classMethod))
continue;
2013-01-19 20:03:57 +08:00
interfaceMethodInfos.AddMethod(ifaceInfo, ifaceMethod, classMethod);
}
}
}
//--- * If there are any virtual methods in the interface that still have empty slots,
//--- see if there are any public virtual methods, but not public virtual newslot
//--- methods, available on this class (directly or inherited) having the same name
//--- and signature, then use these to implement the corresponding methods on the
//--- interface.
methodsDict.Clear();
2013-01-19 20:03:57 +08:00
foreach (var methodInstList in virtualMethodInstances.GetMethods()) {
// This class' method is at the end
for (int i = methodInstList.Count - 1; i >= 0; i--) {
var classMethod = methodInstList[i];
// These methods are guaranteed to be virtual.
// We should allow newslot methods, despite what the official doc says.
2013-01-19 20:03:57 +08:00
if (!classMethod.origMethodDef.IsPublic())
continue;
2012-11-22 16:14:51 +08:00
methodsDict[classMethod.methodRef] = classMethod.origMethodDef;
break;
}
}
foreach (var ifaceInfo in allImplementedInterfaces.Keys) {
2013-01-19 20:03:57 +08:00
foreach (var methodsList in ifaceInfo.typeDef.virtualMethodInstances.GetMethods()) {
if (methodsList.Count < 1)
continue;
var ifaceMethod = methodsList[0].origMethodDef;
2013-01-19 20:03:57 +08:00
if (!ifaceMethod.IsVirtual())
continue;
2013-01-19 20:03:57 +08:00
var ifaceMethodRef = GenericArgsSubstitutor.Create(ifaceMethod.MethodDef, ifaceInfo.typeRef.TryGetGenericInstSig());
MMethodDef classMethod;
2012-11-03 05:53:24 +08:00
if (!methodsDict.TryGetValue(ifaceMethodRef, out classMethod))
continue;
2013-01-19 20:03:57 +08:00
interfaceMethodInfos.AddMethodIfEmpty(ifaceInfo, ifaceMethod, classMethod);
}
}
//--- * Apply all MethodImpls that are specified for this class, thereby placing
//--- explicitly specified virtual methods into the interface in preference to those
//--- inherited or chosen by name matching.
methodsDict.Clear();
2012-11-04 05:49:52 +08:00
var ifaceMethodsDict = new Dictionary<IMethodDefOrRef, MMethodDef>(MethodEqualityComparer.CompareDeclaringTypes);
foreach (var ifaceInfo in allImplementedInterfaces.Keys) {
2012-12-20 01:14:47 +08:00
var git = ifaceInfo.typeRef.TryGetGenericInstSig();
2013-01-19 20:03:57 +08:00
foreach (var ifaceMethod in ifaceInfo.typeDef.methods.GetValues()) {
2012-11-22 16:14:51 +08:00
IMethodDefOrRef ifaceMethodRef = ifaceMethod.MethodDef;
if (git != null)
2013-01-19 20:03:57 +08:00
ifaceMethodRef = SimpleClone(ifaceMethod.MethodDef, ifaceInfo.typeRef);
2012-11-22 16:14:51 +08:00
ifaceMethodsDict[ifaceMethodRef] = ifaceMethod;
}
}
2013-01-19 20:03:57 +08:00
foreach (var classMethod in methods.GetValues()) {
if (!classMethod.IsVirtual())
continue;
foreach (var overrideMethod in classMethod.MethodDef.Overrides) {
MMethodDef ifaceMethod;
2012-11-03 03:10:34 +08:00
if (!ifaceMethodsDict.TryGetValue(overrideMethod.MethodDeclaration, out ifaceMethod)) {
// We couldn't find the interface method (eg. interface not resolved) or
// it overrides a base class method, and not an interface method.
continue;
}
2013-01-19 20:03:57 +08:00
interfaceMethodInfos.AddMethod(overrideMethod.MethodDeclaration.DeclaringType, ifaceMethod, classMethod);
}
}
//--- * If the current class is not abstract and there are any interface methods that
//--- still have empty slots, then the program is invalid.
// Check it anyway. C# requires a method, even if it's abstract. I don't think anyone
// writes pure CIL assemblies.
foreach (var info in interfaceMethodInfos.AllInfos) {
foreach (var pair in info.IfaceMethodToClassMethod) {
if (pair.Value != null)
continue;
2013-01-19 20:03:57 +08:00
if (!ResolvedAllInterfaces() || !ResolvedBaseClasses())
continue;
// Ignore if COM class
if (!TypeDef.IsImport &&
2013-01-19 20:03:57 +08:00
!HasAttribute("System.Runtime.InteropServices.ComImportAttribute") &&
!HasAttribute("System.Runtime.InteropServices.TypeLibTypeAttribute")) {
Logger.w("Could not find interface method {0} ({1:X8}). Type: {2} ({3:X8})",
2013-01-19 20:03:57 +08:00
Utils.RemoveNewlines(pair.Key.methodDef.MethodDef),
pair.Key.methodDef.MethodDef.MDToken.ToInt32(),
2013-01-19 20:03:57 +08:00
Utils.RemoveNewlines(TypeDef),
TypeDef.MDToken.ToInt32());
}
}
}
foreach (var info in interfaceMethodInfos.AllInfos) {
foreach (var pair in info.IfaceMethodToClassMethod) {
if (pair.Value == null)
continue;
if (pair.Key.methodDef.MethodDef.Name != pair.Value.MethodDef.Name)
continue;
2013-01-19 20:03:57 +08:00
groups.Same(pair.Key.methodDef, pair.Value);
}
}
}
2013-01-19 20:03:57 +08:00
bool HasAttribute(string name) {
foreach (var attr in TypeDef.CustomAttributes) {
2012-11-04 05:49:52 +08:00
if (attr.TypeFullName == name)
return true;
}
return false;
}
// Returns true if all interfaces have been resolved
bool? resolvedAllInterfacesResult;
2013-01-19 20:03:57 +08:00
bool ResolvedAllInterfaces() {
if (!resolvedAllInterfacesResult.HasValue) {
resolvedAllInterfacesResult = true; // If we find a circular reference
2013-01-19 20:03:57 +08:00
resolvedAllInterfacesResult = ResolvedAllInterfacesInternal();
}
return resolvedAllInterfacesResult.Value;
}
2013-01-19 20:03:57 +08:00
bool ResolvedAllInterfacesInternal() {
2012-11-17 06:50:52 +08:00
if (TypeDef.Interfaces.Count != interfaces.Count)
return false;
foreach (var ifaceInfo in interfaces) {
2013-01-19 20:03:57 +08:00
if (!ifaceInfo.typeDef.ResolvedAllInterfaces())
return false;
}
return true;
}
// Returns true if all base classes have been resolved
bool? resolvedBaseClassesResult;
2013-01-19 20:03:57 +08:00
bool ResolvedBaseClasses() {
if (!resolvedBaseClassesResult.HasValue) {
resolvedBaseClassesResult = true; // If we find a circular reference
2013-01-19 20:03:57 +08:00
resolvedBaseClassesResult = ResolvedBaseClassesInternal();
}
return resolvedBaseClassesResult.Value;
}
2013-01-19 20:03:57 +08:00
bool ResolvedBaseClassesInternal() {
if (TypeDef.BaseType == null)
return true;
if (baseType == null)
return false;
2013-01-19 20:03:57 +08:00
return baseType.typeDef.ResolvedBaseClasses();
}
2013-01-19 20:03:57 +08:00
MemberRef SimpleClone(MethodDef methodRef, ITypeDefOrRef declaringType) {
if (module == null)
return new MemberRefUser(null, methodRef.Name, methodRef.MethodSig, declaringType);
2012-11-03 03:10:34 +08:00
var mr = new MemberRefUser(module.ModuleDefMD, methodRef.Name, methodRef.MethodSig, declaringType);
return module.ModuleDefMD.UpdateRowId(mr);
}
2013-01-19 20:03:57 +08:00
void InstantiateVirtualMembers(MethodNameGroups groups) {
if (!TypeDef.IsInterface) {
if (baseType != null)
2013-01-19 20:03:57 +08:00
virtualMethodInstances.InitializeFrom(baseType.typeDef.virtualMethodInstances, baseType.typeRef.TryGetGenericInstSig());
// Figure out which methods we override in the base class
2013-01-19 20:03:57 +08:00
foreach (var methodDef in methods.GetValues()) {
if (!methodDef.IsVirtual() || methodDef.IsNewSlot())
continue;
2013-01-19 20:03:57 +08:00
var methodInstList = virtualMethodInstances.Lookup(methodDef.MethodDef);
if (methodInstList == null)
continue;
foreach (var methodInst in methodInstList)
2013-01-19 20:03:57 +08:00
groups.Same(methodDef, methodInst.origMethodDef);
}
}
2013-01-19 20:03:57 +08:00
foreach (var methodDef in methods.GetValues()) {
if (!methodDef.IsVirtual())
continue;
2013-01-19 20:03:57 +08:00
virtualMethodInstances.Add(new MethodInst(methodDef, methodDef.MethodDef));
}
}
2011-11-15 21:26:51 +08:00
}
}