2011-11-15 21:26:51 +08:00
|
|
|
|
/*
|
2012-01-10 06:02:47 +08:00
|
|
|
|
Copyright (C) 2011-2012 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;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
using dot10.DotNet;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
using de4dot.blocks;
|
2011-11-15 21:26:51 +08:00
|
|
|
|
|
2011-12-09 16:02:06 +08:00
|
|
|
|
namespace de4dot.code.renamer.asmmodules {
|
2012-11-04 05:49:52 +08:00
|
|
|
|
struct GenericArgsSubstitutor {
|
|
|
|
|
IList<TypeSig> genericArgs;
|
|
|
|
|
bool updated;
|
|
|
|
|
|
|
|
|
|
public static ITypeDefOrRef create(ITypeDefOrRef type, GenericInstSig git) {
|
2012-11-03 05:53:24 +08:00
|
|
|
|
if (git == null)
|
|
|
|
|
return type;
|
2012-11-04 05:49:52 +08:00
|
|
|
|
return create(type, git.GenericArguments);
|
2012-11-03 05:53:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-04 05:49:52 +08:00
|
|
|
|
public static ITypeDefOrRef create(ITypeDefOrRef type, IList<TypeSig> genericArgs) {
|
2012-11-03 05:53:24 +08:00
|
|
|
|
if (genericArgs == null || genericArgs.Count == 0)
|
|
|
|
|
return type;
|
2012-11-04 05:49:52 +08:00
|
|
|
|
var ts = type as TypeSpec;
|
|
|
|
|
if (ts == null)
|
|
|
|
|
return type;
|
|
|
|
|
var newSig = create(ts.TypeSig, genericArgs);
|
|
|
|
|
return newSig == ts.TypeSig ? type : new TypeSpecUser(newSig);
|
|
|
|
|
}
|
2012-11-03 05:53:24 +08:00
|
|
|
|
|
2012-11-04 05:49:52 +08:00
|
|
|
|
public static TypeSig create(TypeSig type, IList<TypeSig> genericArgs) {
|
|
|
|
|
if (type == null || genericArgs == null || genericArgs.Count == 0)
|
|
|
|
|
return type;
|
|
|
|
|
return new GenericArgsSubstitutor(genericArgs).create(type);
|
2012-11-03 03:10:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-04 05:49:52 +08:00
|
|
|
|
public static IMethodDefOrRef create(IMethodDefOrRef method, GenericInstSig git) {
|
2012-11-03 05:53:24 +08:00
|
|
|
|
if (git == null)
|
|
|
|
|
return method;
|
2012-11-04 05:49:52 +08:00
|
|
|
|
return create(method, git.GenericArguments);
|
2012-11-03 05:53:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-04 05:49:52 +08:00
|
|
|
|
// Creates a new method but keeps declaring type as is
|
|
|
|
|
public static IMethodDefOrRef create(IMethodDefOrRef method, IList<TypeSig> genericArgs) {
|
|
|
|
|
if (method == null || genericArgs == null || genericArgs.Count == 0)
|
2012-11-03 05:53:24 +08:00
|
|
|
|
return method;
|
|
|
|
|
|
2012-11-04 05:49:52 +08:00
|
|
|
|
var sig = method.MethodSig;
|
|
|
|
|
if (sig == null)
|
|
|
|
|
return method;
|
|
|
|
|
|
|
|
|
|
var newSig = new GenericArgsSubstitutor(genericArgs).create(sig);
|
|
|
|
|
if (newSig == sig)
|
|
|
|
|
return method;
|
|
|
|
|
|
|
|
|
|
return new MemberRefUser(method.DeclaringType.OwnerModule, method.Name, newSig, method.DeclaringType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GenericArgsSubstitutor(IList<TypeSig> genericArgs) {
|
|
|
|
|
this.genericArgs = genericArgs;
|
|
|
|
|
this.updated = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TypeSig create(TypeSig type) {
|
|
|
|
|
var newType = create2(type);
|
|
|
|
|
return updated ? newType : type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TypeSig create2(TypeSig type) {
|
|
|
|
|
if (type == null)
|
|
|
|
|
return type;
|
|
|
|
|
TypeSig result;
|
|
|
|
|
|
|
|
|
|
switch (type.ElementType) {
|
|
|
|
|
case ElementType.Void:
|
|
|
|
|
case ElementType.Boolean:
|
|
|
|
|
case ElementType.Char:
|
|
|
|
|
case ElementType.I1:
|
|
|
|
|
case ElementType.U1:
|
|
|
|
|
case ElementType.I2:
|
|
|
|
|
case ElementType.U2:
|
|
|
|
|
case ElementType.I4:
|
|
|
|
|
case ElementType.U4:
|
|
|
|
|
case ElementType.I8:
|
|
|
|
|
case ElementType.U8:
|
|
|
|
|
case ElementType.R4:
|
|
|
|
|
case ElementType.R8:
|
|
|
|
|
case ElementType.String:
|
|
|
|
|
case ElementType.TypedByRef:
|
|
|
|
|
case ElementType.I:
|
|
|
|
|
case ElementType.U:
|
|
|
|
|
case ElementType.Object:
|
|
|
|
|
result = type;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.Ptr:
|
|
|
|
|
result = new PtrSig(create2(type.Next));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.ByRef:
|
|
|
|
|
result = new ByRefSig(create2(type.Next));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.Array:
|
|
|
|
|
var ary = (ArraySig)type;
|
|
|
|
|
result = new ArraySig(ary.Next, ary.Rank, ary.Sizes, ary.LowerBounds);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.SZArray:
|
|
|
|
|
result = new SZArraySig(create2(type.Next));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.Pinned:
|
|
|
|
|
result = new PinnedSig(create2(type.Next));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.ValueType:
|
|
|
|
|
case ElementType.Class:
|
|
|
|
|
result = type;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.Var:
|
|
|
|
|
var varSig = (GenericSig)type;
|
|
|
|
|
if (varSig.Number < (uint)genericArgs.Count) {
|
|
|
|
|
result = genericArgs[(int)varSig.Number];
|
|
|
|
|
updated = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
result = type;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.MVar:
|
|
|
|
|
result = type;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.GenericInst:
|
|
|
|
|
var gis = (GenericInstSig)type;
|
|
|
|
|
var newGis = new GenericInstSig(create2(gis.GenericType) as ClassOrValueTypeSig, gis.GenericArguments.Count);
|
|
|
|
|
for (int i = 0; i < gis.GenericArguments.Count; i++)
|
|
|
|
|
newGis.GenericArguments.Add(create2(gis.GenericArguments[i]));
|
|
|
|
|
result = newGis;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.ValueArray:
|
|
|
|
|
result = new ValueArraySig(type.Next, ((ValueArraySig)type).Size);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.Module:
|
|
|
|
|
result = new ModuleSig(((ModuleSig)type).Index, type.Next);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.CModReqd:
|
|
|
|
|
result = new CModReqdSig(((ModifierSig)type).Modifier, type.Next);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.CModOpt:
|
|
|
|
|
result = new CModOptSig(((ModifierSig)type).Modifier, type.Next);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.FnPtr:
|
|
|
|
|
result = new FnPtrSig(create(((FnPtrSig)type).MethodSig));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ElementType.End:
|
|
|
|
|
case ElementType.R:
|
|
|
|
|
case ElementType.Sentinel:
|
|
|
|
|
case ElementType.Internal:
|
|
|
|
|
default:
|
|
|
|
|
result = type;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MethodSig create(MethodSig sig) {
|
|
|
|
|
if (sig == null)
|
|
|
|
|
return sig;
|
|
|
|
|
var newSig = new MethodSig(sig.GetCallingConvention());
|
|
|
|
|
newSig.RetType = create2(sig.RetType);
|
|
|
|
|
for (int i = 0; i < sig.Params.Count; i++)
|
|
|
|
|
newSig.Params.Add(create2(sig.Params[i]));
|
|
|
|
|
newSig.GenParamCount = sig.GenParamCount;
|
|
|
|
|
if (sig.ParamsAfterSentinel != null) {
|
|
|
|
|
newSig.ParamsAfterSentinel = new List<TypeSig>();
|
|
|
|
|
for (int i = 0; i < sig.ParamsAfterSentinel.Count; i++)
|
|
|
|
|
newSig.ParamsAfterSentinel.Add(create2(sig.ParamsAfterSentinel[i]));
|
|
|
|
|
}
|
|
|
|
|
return updated ? newSig : sig;
|
2012-11-03 03:10:34 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-15 21:26:51 +08:00
|
|
|
|
class TypeInfo {
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public ITypeDefOrRef typeReference;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public MTypeDef typeDef;
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public TypeInfo(ITypeDefOrRef typeReference, MTypeDef typeDef) {
|
2011-11-15 21:26:51 +08:00
|
|
|
|
this.typeReference = typeReference;
|
|
|
|
|
this.typeDef = typeDef;
|
|
|
|
|
}
|
2011-11-17 06:08:27 +08:00
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public TypeInfo(TypeInfo other, GenericInstSig git) {
|
2012-11-04 05:49:52 +08:00
|
|
|
|
this.typeReference = GenericArgsSubstitutor.create(other.typeReference, git);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
this.typeDef = other.typeDef;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int GetHashCode() {
|
|
|
|
|
return typeDef.GetHashCode() +
|
2012-11-03 03:10:34 +08:00
|
|
|
|
new SigComparer().GetHashCode(typeReference);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool Equals(object obj) {
|
|
|
|
|
var other = obj as TypeInfo;
|
|
|
|
|
if (other == null)
|
|
|
|
|
return false;
|
|
|
|
|
return typeDef == other.typeDef &&
|
2012-11-03 03:10:34 +08:00
|
|
|
|
new SigComparer().Equals(typeReference, other.typeReference);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToString() {
|
|
|
|
|
return typeReference.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-23 16:14:50 +08:00
|
|
|
|
class MethodDefKey {
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public readonly MMethodDef methodDef;
|
2012-01-23 16:14:50 +08:00
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public MethodDefKey(MMethodDef methodDef) {
|
2012-01-23 16:14:50 +08:00
|
|
|
|
this.methodDef = methodDef;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int GetHashCode() {
|
2012-11-03 03:10:34 +08:00
|
|
|
|
return MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(methodDef.MethodDef);
|
2012-01-23 16:14:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2012-01-23 16:14:50 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-17 06:08:27 +08:00
|
|
|
|
class MethodInst {
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public MMethodDef origMethodDef;
|
2012-11-04 05:49:52 +08:00
|
|
|
|
public IMethodDefOrRef methodReference;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
|
2012-11-04 05:49:52 +08:00
|
|
|
|
public MethodInst(MMethodDef origMethodDef, IMethodDefOrRef methodReference) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
this.origMethodDef = origMethodDef;
|
|
|
|
|
this.methodReference = methodReference;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToString() {
|
|
|
|
|
return methodReference.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class MethodInstances {
|
2012-11-04 05:49:52 +08:00
|
|
|
|
Dictionary<IMethodDefOrRef, List<MethodInst>> methodInstances = new Dictionary<IMethodDefOrRef, List<MethodInst>>(MethodEqualityComparer.DontCompareDeclaringTypes);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public void initializeFrom(MethodInstances other, GenericInstSig git) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
foreach (var list in other.methodInstances.Values) {
|
|
|
|
|
foreach (var methodInst in list) {
|
2012-11-04 05:49:52 +08:00
|
|
|
|
var newMethod = GenericArgsSubstitutor.create(methodInst.methodReference, git);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
add(new MethodInst(methodInst.origMethodDef, newMethod));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void add(MethodInst methodInst) {
|
|
|
|
|
List<MethodInst> list;
|
2012-11-03 03:10:34 +08:00
|
|
|
|
var key = methodInst.methodReference;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (methodInst.origMethodDef.isNewSlot() || !methodInstances.TryGetValue(key, out list))
|
|
|
|
|
methodInstances[key] = list = new List<MethodInst>();
|
|
|
|
|
list.Add(methodInst);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-04 05:49:52 +08:00
|
|
|
|
public List<MethodInst> lookup(IMethodDefOrRef methodReference) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
List<MethodInst> list;
|
2012-11-03 03:10:34 +08:00
|
|
|
|
methodInstances.TryGetValue(methodReference, out list);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IEnumerable<List<MethodInst>> getMethods() {
|
|
|
|
|
return methodInstances.Values;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-23 16:14:50 +08:00
|
|
|
|
// Keeps track of which methods of an interface that have been implemented
|
2011-11-17 06:08:27 +08:00
|
|
|
|
class InterfaceMethodInfo {
|
|
|
|
|
TypeInfo iface;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
Dictionary<MethodDefKey, MMethodDef> ifaceMethodToClassMethod = new Dictionary<MethodDefKey, MMethodDef>();
|
2011-11-17 06:08:27 +08:00
|
|
|
|
|
|
|
|
|
public TypeInfo IFace {
|
|
|
|
|
get { return iface; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public Dictionary<MethodDefKey, MMethodDef> IfaceMethodToClassMethod {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
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)
|
2012-01-23 16:14:50 +08:00
|
|
|
|
ifaceMethodToClassMethod[new MethodDefKey(methodDef)] = null;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public InterfaceMethodInfo(TypeInfo iface, InterfaceMethodInfo other) {
|
|
|
|
|
this.iface = iface;
|
|
|
|
|
foreach (var key in other.ifaceMethodToClassMethod.Keys)
|
|
|
|
|
ifaceMethodToClassMethod[key] = other.ifaceMethodToClassMethod[key];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-22 15:57:10 +08:00
|
|
|
|
// Returns the previous method, or null if none
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public MMethodDef addMethod(MMethodDef ifaceMethod, MMethodDef classMethod) {
|
2012-01-23 16:14:50 +08:00
|
|
|
|
var ifaceKey = new MethodDefKey(ifaceMethod);
|
|
|
|
|
if (!ifaceMethodToClassMethod.ContainsKey(ifaceKey))
|
2011-11-17 06:08:27 +08:00
|
|
|
|
throw new ApplicationException("Could not find interface method");
|
2011-11-22 15:57:10 +08:00
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
MMethodDef oldMethod;
|
2012-01-23 16:14:50 +08:00
|
|
|
|
ifaceMethodToClassMethod.TryGetValue(ifaceKey, out oldMethod);
|
|
|
|
|
ifaceMethodToClassMethod[ifaceKey] = classMethod;
|
2011-11-22 15:57:10 +08:00
|
|
|
|
return oldMethod;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public void addMethodIfEmpty(MMethodDef ifaceMethod, MMethodDef classMethod) {
|
2012-01-23 16:14:50 +08:00
|
|
|
|
if (ifaceMethodToClassMethod[new MethodDefKey(ifaceMethod)] == null)
|
2011-11-22 15:57:10 +08:00
|
|
|
|
addMethod(ifaceMethod, classMethod);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToString() {
|
|
|
|
|
return iface.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class InterfaceMethodInfos {
|
2012-11-03 03:10:34 +08:00
|
|
|
|
Dictionary<ITypeDefOrRef, InterfaceMethodInfo> interfaceMethods = new Dictionary<ITypeDefOrRef, InterfaceMethodInfo>(TypeEqualityComparer.Instance);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
|
|
|
|
|
public IEnumerable<InterfaceMethodInfo> AllInfos {
|
|
|
|
|
get { return interfaceMethods.Values; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public void initializeFrom(InterfaceMethodInfos other, GenericInstSig git) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
foreach (var pair in other.interfaceMethods) {
|
|
|
|
|
var oldTypeInfo = pair.Value.IFace;
|
|
|
|
|
var newTypeInfo = new TypeInfo(oldTypeInfo, git);
|
2012-11-03 03:10:34 +08:00
|
|
|
|
var oldKey = oldTypeInfo.typeReference;
|
|
|
|
|
var newKey = newTypeInfo.typeReference;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
|
|
|
|
|
InterfaceMethodInfo newMethodsInfo = new InterfaceMethodInfo(newTypeInfo, other.interfaceMethods[oldKey]);
|
|
|
|
|
if (interfaceMethods.ContainsKey(newKey))
|
|
|
|
|
newMethodsInfo.merge(interfaceMethods[newKey]);
|
|
|
|
|
interfaceMethods[newKey] = newMethodsInfo;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void addInterface(TypeInfo iface) {
|
2012-11-03 03:10:34 +08:00
|
|
|
|
var key = iface.typeReference;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (!interfaceMethods.ContainsKey(key))
|
|
|
|
|
interfaceMethods[key] = new InterfaceMethodInfo(iface);
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-22 15:57:10 +08:00
|
|
|
|
// Returns the previous classMethod, or null if none
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public MMethodDef addMethod(TypeInfo iface, MMethodDef ifaceMethod, MMethodDef classMethod) {
|
2011-11-22 15:57:10 +08:00
|
|
|
|
return addMethod(iface.typeReference, ifaceMethod, classMethod);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-22 15:57:10 +08:00
|
|
|
|
// Returns the previous classMethod, or null if none
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public MMethodDef addMethod(ITypeDefOrRef iface, MMethodDef ifaceMethod, MMethodDef classMethod) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
InterfaceMethodInfo info;
|
2012-11-03 03:10:34 +08:00
|
|
|
|
if (!interfaceMethods.TryGetValue(iface, out info))
|
2011-11-17 06:08:27 +08:00
|
|
|
|
throw new ApplicationException("Could not find interface");
|
2011-11-22 15:57:10 +08:00
|
|
|
|
return info.addMethod(ifaceMethod, classMethod);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public void addMethodIfEmpty(TypeInfo iface, MMethodDef ifaceMethod, MMethodDef classMethod) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
InterfaceMethodInfo info;
|
2012-11-03 03:10:34 +08:00
|
|
|
|
if (!interfaceMethods.TryGetValue(iface.typeReference, out info))
|
2011-11-17 06:08:27 +08:00
|
|
|
|
throw new ApplicationException("Could not find interface");
|
|
|
|
|
info.addMethodIfEmpty(ifaceMethod, classMethod);
|
|
|
|
|
}
|
2011-11-15 21:26:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
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();
|
2012-11-02 22:57:11 +08:00
|
|
|
|
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
|
2012-11-02 22:57:11 +08:00
|
|
|
|
internal IList<MTypeDef> derivedTypes = new List<MTypeDef>();
|
2011-11-15 21:26:51 +08:00
|
|
|
|
Module module;
|
|
|
|
|
|
2011-11-17 06:08:27 +08:00
|
|
|
|
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; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public IList<MGenericParamDef> GenericParams {
|
2011-11-17 11:17:03 +08:00
|
|
|
|
get { return genericParams; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public IEnumerable<MTypeDef> NestedTypes {
|
2011-11-15 21:26:51 +08:00
|
|
|
|
get { return types.getSorted(); }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public MTypeDef NestingType { get; set; }
|
2011-11-15 21:26:51 +08:00
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public TypeDef TypeDef {
|
|
|
|
|
get { return (TypeDef)memberReference; }
|
2011-11-15 21:26:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public IEnumerable<MEventDef> AllEvents {
|
2012-01-01 19:09:16 +08:00
|
|
|
|
get { return events.getValues(); }
|
2011-11-18 23:55:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public IEnumerable<MFieldDef> AllFields {
|
2012-01-01 19:09:16 +08:00
|
|
|
|
get { return fields.getValues(); }
|
2011-11-18 23:55:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public IEnumerable<MMethodDef> AllMethods {
|
2012-01-01 19:09:16 +08:00
|
|
|
|
get { return methods.getValues(); }
|
2011-11-18 23:55:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public IEnumerable<MPropertyDef> AllProperties {
|
2012-01-01 19:09:16 +08:00
|
|
|
|
get { return properties.getValues(); }
|
2011-11-18 23:55:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public IEnumerable<MEventDef> AllEventsSorted {
|
2011-11-18 23:55:54 +08:00
|
|
|
|
get { return events.getSorted(); }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public IEnumerable<MFieldDef> AllFieldsSorted {
|
2011-11-18 23:55:54 +08:00
|
|
|
|
get { return fields.getSorted(); }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public IEnumerable<MMethodDef> AllMethodsSorted {
|
2011-11-18 23:55:54 +08:00
|
|
|
|
get { return methods.getSorted(); }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public IEnumerable<MPropertyDef> AllPropertiesSorted {
|
2011-11-18 23:55:54 +08:00
|
|
|
|
get { return properties.getSorted(); }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public MTypeDef(TypeDef typeDefinition, Module module, int index)
|
2011-11-15 21:26:51 +08:00
|
|
|
|
: base(typeDefinition, null, index) {
|
|
|
|
|
this.module = module;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
genericParams = MGenericParamDef.createGenericParamDefList(TypeDef.GenericParams);
|
2011-11-15 21:26:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +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));
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +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);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public void add(MEventDef e) {
|
2011-11-15 21:26:51 +08:00
|
|
|
|
events.add(e);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public void add(MFieldDef f) {
|
2011-11-15 21:26:51 +08:00
|
|
|
|
fields.add(f);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public void add(MMethodDef m) {
|
2011-11-15 21:26:51 +08:00
|
|
|
|
methods.add(m);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public void add(MPropertyDef p) {
|
2011-11-15 21:26:51 +08:00
|
|
|
|
properties.add(p);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public void add(MTypeDef t) {
|
2011-11-15 21:26:51 +08:00
|
|
|
|
types.add(t);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public MMethodDef findMethod(MemberRef mr) {
|
2011-11-15 21:26:51 +08:00
|
|
|
|
return methods.find(mr);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-04 07:50:24 +08:00
|
|
|
|
public MMethodDef findMethod(IMethodDefOrRef md) {
|
|
|
|
|
return methods.find(md);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public MMethodDef findMethod(MethodDef md) {
|
|
|
|
|
return methods.find(md);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MMethodDef findAnyMethod(MemberRef mr) {
|
2011-12-28 20:24:02 +08:00
|
|
|
|
return methods.findAny(mr);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public MFieldDef findField(MemberRef fr) {
|
2011-11-15 21:26:51 +08:00
|
|
|
|
return fields.find(fr);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public MFieldDef findAnyField(MemberRef fr) {
|
2011-12-28 20:24:02 +08:00
|
|
|
|
return fields.findAny(fr);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public MPropertyDef find(PropertyDef pr) {
|
2011-11-21 17:36:23 +08:00
|
|
|
|
return properties.find(pr);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public MPropertyDef findAny(PropertyDef pr) {
|
2011-12-28 20:24:02 +08:00
|
|
|
|
return properties.findAny(pr);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public MEventDef find(EventDef er) {
|
2011-11-23 13:41:28 +08:00
|
|
|
|
return events.find(er);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
public MEventDef findAny(EventDef er) {
|
2011-12-28 20:24:02 +08:00
|
|
|
|
return events.findAny(er);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public MPropertyDef create(PropertyDef newProp) {
|
2011-12-28 20:24:02 +08:00
|
|
|
|
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");
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
var propDef = new MPropertyDef(newProp, this, properties.Count);
|
2011-11-21 17:36:23 +08:00
|
|
|
|
add(propDef);
|
2012-11-02 22:57:11 +08:00
|
|
|
|
TypeDef.Properties.Add(newProp);
|
2011-11-21 17:36:23 +08:00
|
|
|
|
return propDef;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public MEventDef create(EventDef newEvent) {
|
2011-12-28 20:24:02 +08:00
|
|
|
|
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");
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
var eventDef = new MEventDef(newEvent, this, events.Count);
|
2011-11-23 13:41:28 +08:00
|
|
|
|
add(eventDef);
|
2012-11-02 22:57:11 +08:00
|
|
|
|
TypeDef.Events.Add(newEvent);
|
2011-11-23 13:41:28 +08:00
|
|
|
|
return eventDef;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-15 21:26:51 +08:00
|
|
|
|
public void addMembers() {
|
2012-11-02 22:57:11 +08:00
|
|
|
|
var type = TypeDef;
|
2011-11-15 21:26:51 +08:00
|
|
|
|
|
|
|
|
|
for (int i = 0; i < type.Events.Count; i++)
|
2012-11-02 22:57:11 +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++)
|
2012-11-02 22:57:11 +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++)
|
2012-11-02 22:57:11 +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++)
|
2012-11-02 22:57:11 +08:00
|
|
|
|
add(new MPropertyDef(type.Properties[i], this, i));
|
2011-11-18 23:55:54 +08:00
|
|
|
|
|
2012-01-01 19:09:16 +08:00
|
|
|
|
foreach (var propDef in properties.getValues()) {
|
2011-11-18 23:55:54 +08:00
|
|
|
|
foreach (var method in propDef.methodDefinitions()) {
|
2012-11-03 03:10:34 +08:00
|
|
|
|
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;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (method == propDef.PropertyDef.GetMethod)
|
2011-11-21 17:36:23 +08:00
|
|
|
|
propDef.GetMethod = methodDef;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (method == propDef.PropertyDef.SetMethod)
|
2011-11-21 17:36:23 +08:00
|
|
|
|
propDef.SetMethod = methodDef;
|
2011-11-18 23:55:54 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-01 19:09:16 +08:00
|
|
|
|
foreach (var eventDef in events.getValues()) {
|
2011-11-18 23:55:54 +08:00
|
|
|
|
foreach (var method in eventDef.methodDefinitions()) {
|
2012-11-03 03:10:34 +08:00
|
|
|
|
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;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (method == eventDef.EventDef.AddMethod)
|
2011-11-21 17:36:23 +08:00
|
|
|
|
eventDef.AddMethod = methodDef;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (method == eventDef.EventDef.RemoveMethod)
|
2011-11-21 17:36:23 +08:00
|
|
|
|
eventDef.RemoveMethod = methodDef;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (method == eventDef.EventDef.InvokeMethod)
|
2011-11-21 17:36:23 +08:00
|
|
|
|
eventDef.RaiseMethod = methodDef;
|
2011-11-18 23:55:54 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void onTypesRenamed() {
|
|
|
|
|
events.onTypesRenamed();
|
2011-11-21 17:36:23 +08:00
|
|
|
|
properties.onTypesRenamed();
|
2011-11-18 23:55:54 +08:00
|
|
|
|
fields.onTypesRenamed();
|
|
|
|
|
methods.onTypesRenamed();
|
|
|
|
|
types.onTypesRenamed();
|
2011-11-15 21:26:51 +08:00
|
|
|
|
}
|
2011-11-17 06:08:27 +08:00
|
|
|
|
|
2011-11-17 11:17:03 +08:00
|
|
|
|
public bool isNested() {
|
|
|
|
|
return NestingType != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool isGlobalType() {
|
|
|
|
|
if (!isNested())
|
2012-11-02 22:57:11 +08:00
|
|
|
|
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:
|
|
|
|
|
return NestingType.isGlobalType();
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-08 20:23:01 +08:00
|
|
|
|
public void initializeVirtualMembers(MethodNameGroups groups, IResolver resolver) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (initializeVirtualMembersCalled)
|
|
|
|
|
return;
|
|
|
|
|
initializeVirtualMembersCalled = true;
|
|
|
|
|
|
|
|
|
|
foreach (var iface in interfaces)
|
2012-03-08 20:23:01 +08:00
|
|
|
|
iface.typeDef.initializeVirtualMembers(groups, resolver);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (baseType != null)
|
2012-03-08 20:23:01 +08:00
|
|
|
|
baseType.typeDef.initializeVirtualMembers(groups, resolver);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
|
2012-01-01 19:09:16 +08:00
|
|
|
|
foreach (var methodDef in methods.getValues()) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (methodDef.isVirtual())
|
2012-03-08 20:23:01 +08:00
|
|
|
|
groups.add(methodDef);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-03-08 20:23:01 +08:00
|
|
|
|
instantiateVirtualMembers(groups);
|
|
|
|
|
initializeInterfaceMethods(groups);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void initializeAllInterfaces() {
|
|
|
|
|
if (baseType != null)
|
|
|
|
|
initializeInterfaces(baseType);
|
|
|
|
|
|
|
|
|
|
foreach (var iface in interfaces) {
|
|
|
|
|
allImplementedInterfaces[iface] = true;
|
|
|
|
|
interfaceMethodInfos.addInterface(iface);
|
|
|
|
|
initializeInterfaces(iface);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void initializeInterfaces(TypeInfo typeInfo) {
|
2012-11-03 03:10:34 +08:00
|
|
|
|
var git = typeInfo.typeReference.ToGenericInstSig();
|
2011-11-17 06:08:27 +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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-08 20:23:01 +08:00
|
|
|
|
void initializeInterfaceMethods(MethodNameGroups groups) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
initializeAllInterfaces();
|
|
|
|
|
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (TypeDef.IsInterface)
|
2011-11-17 06:08:27 +08:00
|
|
|
|
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);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
|
|
|
|
|
//--- * 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();
|
2012-01-01 19:09:16 +08:00
|
|
|
|
foreach (var method in methods.getValues()) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (!method.isPublic() || !method.isVirtual() || !method.isNewSlot())
|
|
|
|
|
continue;
|
2012-11-03 05:53:24 +08:00
|
|
|
|
methodsDict[method.MethodDef] = method;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var ifaceInfo in interfaces) {
|
|
|
|
|
foreach (var methodsList in ifaceInfo.typeDef.virtualMethodInstances.getMethods()) {
|
|
|
|
|
if (methodsList.Count != 1) // Never happens
|
|
|
|
|
throw new ApplicationException("Interface with more than one method in the list");
|
|
|
|
|
var methodInst = methodsList[0];
|
|
|
|
|
var ifaceMethod = methodInst.origMethodDef;
|
|
|
|
|
if (!ifaceMethod.isVirtual())
|
|
|
|
|
continue;
|
2012-11-04 05:49:52 +08:00
|
|
|
|
var ifaceMethodReference = GenericArgsSubstitutor.create(methodInst.methodReference, ifaceInfo.typeReference.ToGenericInstSig());
|
2012-11-02 22:57:11 +08:00
|
|
|
|
MMethodDef classMethod;
|
2012-11-03 05:53:24 +08:00
|
|
|
|
if (!methodsDict.TryGetValue(ifaceMethodReference, out classMethod))
|
2011-11-17 06:08:27 +08:00
|
|
|
|
continue;
|
|
|
|
|
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();
|
|
|
|
|
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.
|
|
|
|
|
if (!classMethod.origMethodDef.isPublic())
|
|
|
|
|
continue;
|
2012-11-03 05:53:24 +08:00
|
|
|
|
methodsDict[classMethod.methodReference] = classMethod.origMethodDef;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
foreach (var ifaceInfo in allImplementedInterfaces.Keys) {
|
|
|
|
|
foreach (var methodsList in ifaceInfo.typeDef.virtualMethodInstances.getMethods()) {
|
|
|
|
|
if (methodsList.Count != 1) // Never happens
|
|
|
|
|
throw new ApplicationException("Interface with more than one method in the list");
|
|
|
|
|
var ifaceMethod = methodsList[0].origMethodDef;
|
|
|
|
|
if (!ifaceMethod.isVirtual())
|
|
|
|
|
continue;
|
2012-11-04 05:49:52 +08:00
|
|
|
|
var ifaceMethodRef = GenericArgsSubstitutor.create(ifaceMethod.MethodDef, ifaceInfo.typeReference.ToGenericInstSig());
|
2012-11-02 22:57:11 +08:00
|
|
|
|
MMethodDef classMethod;
|
2012-11-03 05:53:24 +08:00
|
|
|
|
if (!methodsDict.TryGetValue(ifaceMethodRef, out classMethod))
|
2011-11-17 06:08:27 +08:00
|
|
|
|
continue;
|
|
|
|
|
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);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
foreach (var ifaceInfo in allImplementedInterfaces.Keys) {
|
2012-11-03 03:10:34 +08:00
|
|
|
|
var git = ifaceInfo.typeReference.ToGenericInstSig();
|
2012-01-01 19:09:16 +08:00
|
|
|
|
foreach (var ifaceMethod in ifaceInfo.typeDef.methods.getValues()) {
|
2012-11-04 05:49:52 +08:00
|
|
|
|
IMethodDefOrRef ifaceMethodReference = ifaceMethod.MethodDef;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (git != null)
|
2012-11-03 03:10:34 +08:00
|
|
|
|
ifaceMethodReference = simpleClone(ifaceMethod.MethodDef, ifaceInfo.typeReference);
|
|
|
|
|
ifaceMethodsDict[ifaceMethodReference] = ifaceMethod;
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-01-01 19:09:16 +08:00
|
|
|
|
foreach (var classMethod in methods.getValues()) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (!classMethod.isVirtual())
|
|
|
|
|
continue;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
foreach (var overrideMethod in classMethod.MethodDef.Overrides) {
|
|
|
|
|
MMethodDef ifaceMethod;
|
2012-11-03 03:10:34 +08:00
|
|
|
|
if (!ifaceMethodsDict.TryGetValue(overrideMethod.MethodDeclaration, out ifaceMethod)) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
// We couldn't find the interface method (eg. interface not resolved) or
|
|
|
|
|
// it overrides a base class method, and not an interface method.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
interfaceMethodInfos.addMethod(overrideMethod.MethodDeclaration.DeclaringType, ifaceMethod, classMethod);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- * 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;
|
|
|
|
|
if (!resolvedAllInterfaces() || !resolvedBaseClasses())
|
|
|
|
|
continue;
|
|
|
|
|
// Ignore if COM class
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (!TypeDef.IsImport &&
|
2012-01-09 13:13:55 +08:00
|
|
|
|
!hasAttribute("System.Runtime.InteropServices.ComImportAttribute") &&
|
2012-01-17 12:44:22 +08:00
|
|
|
|
!hasAttribute("System.Runtime.InteropServices.TypeLibTypeAttribute")) {
|
|
|
|
|
Log.w("Could not find interface method {0} ({1:X8}). Type: {2} ({3:X8})",
|
2012-11-02 22:57:11 +08:00
|
|
|
|
Utils.removeNewlines(pair.Key.methodDef.MethodDef),
|
|
|
|
|
pair.Key.methodDef.MethodDef.MDToken.ToInt32(),
|
|
|
|
|
Utils.removeNewlines(TypeDef),
|
|
|
|
|
TypeDef.MDToken.ToInt32());
|
2012-01-17 12:44:22 +08:00
|
|
|
|
}
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var info in interfaceMethodInfos.AllInfos) {
|
|
|
|
|
foreach (var pair in info.IfaceMethodToClassMethod) {
|
|
|
|
|
if (pair.Value == null)
|
|
|
|
|
continue;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (pair.Key.methodDef.MethodDef.Name != pair.Value.MethodDef.Name)
|
2011-11-17 06:08:27 +08:00
|
|
|
|
continue;
|
2012-03-08 20:23:01 +08:00
|
|
|
|
groups.same(pair.Key.methodDef, pair.Value);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool hasAttribute(string name) {
|
2012-11-02 22:57:11 +08:00
|
|
|
|
foreach (var attr in TypeDef.CustomAttributes) {
|
2012-11-04 05:49:52 +08:00
|
|
|
|
if (attr.TypeFullName == name)
|
2011-11-17 06:08:27 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns true if all interfaces have been resolved
|
|
|
|
|
bool? resolvedAllInterfacesResult;
|
|
|
|
|
bool resolvedAllInterfaces() {
|
|
|
|
|
if (!resolvedAllInterfacesResult.HasValue) {
|
|
|
|
|
resolvedAllInterfacesResult = true; // If we find a circular reference
|
|
|
|
|
resolvedAllInterfacesResult = resolvedAllInterfacesInternal();
|
|
|
|
|
}
|
|
|
|
|
return resolvedAllInterfacesResult.Value;
|
|
|
|
|
}
|
|
|
|
|
bool resolvedAllInterfacesInternal() {
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (TypeDef.InterfaceImpls.Count != interfaces.Count)
|
2011-11-17 06:08:27 +08:00
|
|
|
|
return false;
|
|
|
|
|
foreach (var ifaceInfo in interfaces) {
|
|
|
|
|
if (!ifaceInfo.typeDef.resolvedAllInterfaces())
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns true if all base classes have been resolved
|
|
|
|
|
bool? resolvedBaseClassesResult;
|
|
|
|
|
bool resolvedBaseClasses() {
|
|
|
|
|
if (!resolvedBaseClassesResult.HasValue) {
|
|
|
|
|
resolvedBaseClassesResult = true; // If we find a circular reference
|
|
|
|
|
resolvedBaseClassesResult = resolvedBaseClassesInternal();
|
|
|
|
|
}
|
|
|
|
|
return resolvedBaseClassesResult.Value;
|
|
|
|
|
}
|
|
|
|
|
bool resolvedBaseClassesInternal() {
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (TypeDef.BaseType == null)
|
2011-11-17 06:08:27 +08:00
|
|
|
|
return true;
|
|
|
|
|
if (baseType == null)
|
|
|
|
|
return false;
|
|
|
|
|
return baseType.typeDef.resolvedBaseClasses();
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 03:10:34 +08:00
|
|
|
|
MemberRef simpleClone(MethodDef methodRef, ITypeDefOrRef declaringType) {
|
|
|
|
|
var mr = new MemberRefUser(module.ModuleDefMD, methodRef.Name, methodRef.MethodSig, declaringType);
|
|
|
|
|
return module.ModuleDefMD.UpdateRowId(mr);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-03-08 20:23:01 +08:00
|
|
|
|
void instantiateVirtualMembers(MethodNameGroups groups) {
|
2012-11-02 22:57:11 +08:00
|
|
|
|
if (!TypeDef.IsInterface) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (baseType != null)
|
2012-11-03 03:10:34 +08:00
|
|
|
|
virtualMethodInstances.initializeFrom(baseType.typeDef.virtualMethodInstances, baseType.typeReference.ToGenericInstSig());
|
2011-11-17 06:08:27 +08:00
|
|
|
|
|
|
|
|
|
// Figure out which methods we override in the base class
|
2012-01-01 19:09:16 +08:00
|
|
|
|
foreach (var methodDef in methods.getValues()) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (!methodDef.isVirtual() || methodDef.isNewSlot())
|
|
|
|
|
continue;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
var methodInstList = virtualMethodInstances.lookup(methodDef.MethodDef);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (methodInstList == null)
|
|
|
|
|
continue;
|
|
|
|
|
foreach (var methodInst in methodInstList)
|
2012-03-08 20:23:01 +08:00
|
|
|
|
groups.same(methodDef, methodInst.origMethodDef);
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-01 19:09:16 +08:00
|
|
|
|
foreach (var methodDef in methods.getValues()) {
|
2011-11-17 06:08:27 +08:00
|
|
|
|
if (!methodDef.isVirtual())
|
|
|
|
|
continue;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
virtualMethodInstances.add(new MethodInst(methodDef, methodDef.MethodDef));
|
2011-11-17 06:08:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-11-15 21:26:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|