Update the code that renames virtual methods, props, events

This commit is contained in:
de4dot 2011-11-22 08:14:34 +01:00
parent a4747aaeef
commit 45cd6bf211
8 changed files with 203 additions and 234 deletions

View File

@ -52,11 +52,9 @@ namespace de4dot.renamer {
}
}
public ExistingNames clone() {
var cn = new ExistingNames();
foreach (var key in allNames.Keys)
cn.allNames[key] = true;
return cn;
public void merge(ExistingNames other) {
foreach (var key in other.allNames.Keys)
allNames[key] = true;
}
}
}

View File

@ -23,7 +23,6 @@ using de4dot.blocks;
namespace de4dot.renamer {
interface INameCreator {
INameCreator clone();
string create();
}
@ -34,70 +33,53 @@ namespace de4dot.renamer {
this.name = name;
}
public INameCreator clone() {
return this;
}
public string create() {
return name;
}
}
class GlobalNameCreator : INameCreator {
INameCreator other;
abstract class NameCreatorCounter : INameCreator {
protected int num;
public GlobalNameCreator(INameCreator other) {
this.other = other;
}
public abstract string create();
public INameCreator clone() {
public NameCreatorCounter merge(NameCreatorCounter other) {
if (num < other.num)
num = other.num;
return this;
}
public string create() {
return other.create();
}
}
class GenericParamNameCreator : INameCreator {
class GenericParamNameCreator : NameCreatorCounter {
static string[] names = new string[] { "T", "U", "V", "W", "X", "Y", "Z" };
int index = 0;
public string create() {
if (index < names.Length)
return names[index++];
return string.Format("T{0}", index++);
}
public INameCreator clone() {
var rv = new GenericParamNameCreator();
rv.index = index;
return rv;
public override string create() {
if (num < names.Length)
return names[num++];
return string.Format("T{0}", num++);
}
}
class NameCreator : INameCreator {
class NameCreator : NameCreatorCounter {
string prefix;
int num;
public NameCreator(string prefix, int num = 0) {
this.prefix = prefix;
this.num = num;
}
public INameCreator clone() {
public NameCreator clone() {
return new NameCreator(prefix, num);
}
public string create() {
public override string create() {
return prefix + num++;
}
}
// Like NameCreator but don't add the counter the first time
class NameCreator2 : INameCreator {
class NameCreator2 : NameCreatorCounter {
string prefix;
int num;
const string separator = "_";
public NameCreator2(string prefix, int num = 0) {
@ -105,11 +87,7 @@ namespace de4dot.renamer {
this.num = num;
}
public INameCreator clone() {
return new NameCreator2(prefix, num);
}
public string create() {
public override string create() {
string rv;
if (num == 0)
rv = prefix;
@ -129,18 +107,18 @@ namespace de4dot.renamer {
class NameInfo {
public string name;
public INameCreator nameCreator;
public NameInfo(string name, INameCreator nameCreator) {
public NameCreator nameCreator;
public NameInfo(string name, NameCreator nameCreator) {
this.name = name;
this.nameCreator = nameCreator;
}
}
public void add(string name, INameCreator nameCreator) {
public void add(string name, NameCreator nameCreator) {
nameInfos.Add(new NameInfo(name, nameCreator));
}
public INameCreator find(string typeName) {
public NameCreator find(string typeName) {
foreach (var nameInfo in nameInfos) {
if (typeName.Contains(nameInfo.name))
return nameInfo.nameCreator;
@ -152,12 +130,12 @@ namespace de4dot.renamer {
class TypeNameCreator : ITypeNameCreator {
ExistingNames existingNames;
INameCreator createUnknownTypeName;
INameCreator createEnumName;
INameCreator createStructName;
INameCreator createDelegateName;
INameCreator createClassName;
INameCreator createInterfaceName;
NameCreator createUnknownTypeName;
NameCreator createEnumName;
NameCreator createStructName;
NameCreator createDelegateName;
NameCreator createClassName;
NameCreator createInterfaceName;
NameInfos nameInfos = new NameInfos();
public TypeNameCreator(ExistingNames existingNames) {
@ -181,7 +159,7 @@ namespace de4dot.renamer {
nameInfos.add(name, createNameCreator(name));
}
protected virtual INameCreator createNameCreator(string prefix) {
protected virtual NameCreator createNameCreator(string prefix) {
return new NameCreator(prefix);
}
@ -190,7 +168,7 @@ namespace de4dot.renamer {
return existingNames.getName(typeDefinition.Name, nameCreator);
}
INameCreator getNameCreator(TypeDefinition typeDefinition, string newBaseTypeName) {
NameCreator getNameCreator(TypeDefinition typeDefinition, string newBaseTypeName) {
var nameCreator = createUnknownTypeName;
if (typeDefinition.IsEnum)
nameCreator = createEnumName;
@ -222,8 +200,8 @@ namespace de4dot.renamer {
: base(existingNames) {
}
protected override INameCreator createNameCreator(string prefix) {
return new GlobalNameCreator(base.createNameCreator("G" + prefix));
protected override NameCreator createNameCreator(string prefix) {
return base.createNameCreator("G" + prefix);
}
}
}

View File

@ -604,9 +604,6 @@ namespace de4dot.renamer {
prepareRenameEntryPoints();
foreach (var typeDef in modules.BaseTypes)
memberInfos.type(typeDef).variableNameState = new VariableNameState();
foreach (var typeDef in modules.AllTypes)
prepareRenameMembers(typeDef);
@ -638,68 +635,92 @@ namespace de4dot.renamer {
return allScopes;
}
class ScopeHelper {
MemberInfos memberInfos;
Dictionary<TypeDef, bool> visited = new Dictionary<TypeDef, bool>();
Dictionary<MethodDef, MethodNameScope> methodToScope;
List<MethodNameScope> scopes = new List<MethodNameScope>();
IEnumerable<TypeDef> allTypes;
Action<MethodNameScope> func;
public ScopeHelper(MemberInfos memberInfos, IEnumerable<TypeDef> allTypes) {
this.memberInfos = memberInfos;
this.allTypes = allTypes;
}
public void add(MethodNameScope scope) {
scopes.Add(scope);
}
public void visitAll(Action<MethodNameScope> func) {
this.func = func;
visited.Clear();
methodToScope = new Dictionary<MethodDef, MethodNameScope>();
foreach (var scope in scopes) {
foreach (var method in scope.Methods)
methodToScope[method] = scope;
}
foreach (var type in allTypes)
visit(type);
}
void visit(TypeDef type) {
if (visited.ContainsKey(type))
return;
visited[type] = true;
foreach (var ifaceInfo in type.interfaces)
visit(ifaceInfo.typeDef);
if (type.baseType != null)
visit(type.baseType.typeDef);
TypeInfo info;
if (!memberInfos.tryGetType(type, out info))
return;
info.mergeState();
foreach (var method in type.AllMethodsSorted) {
MethodNameScope scope;
if (!methodToScope.TryGetValue(method, out scope))
continue;
foreach (var m in scope.Methods)
methodToScope.Remove(m);
func(scope);
}
}
}
void prepareRenameVirtualMethods(MethodNameScopes scopes) {
var allScopes = getSorted(scopes);
var virtualMethods = new List<MethodNameScope>();
var ifaceMethods = new List<MethodNameScope>();
var propMethods = new List<MethodNameScope>();
var eventMethods = new List<MethodNameScope>();
var virtualMethods = new ScopeHelper(memberInfos, modules.AllTypes);
var ifaceMethods = new ScopeHelper(memberInfos, modules.AllTypes);
var propMethods = new ScopeHelper(memberInfos, modules.AllTypes);
var eventMethods = new ScopeHelper(memberInfos, modules.AllTypes);
foreach (var scope in allScopes) {
if (scope.hasNonRenamableMethod())
continue;
else if (scope.hasPropertyMethod() && getPropertyMethodType(scope.Methods[0]) != PropertyMethodType.Other)
propMethods.Add(scope);
propMethods.add(scope);
else if (scope.hasEventMethod())
eventMethods.Add(scope);
eventMethods.add(scope);
else if (scope.hasInterfaceMethod())
ifaceMethods.Add(scope);
ifaceMethods.add(scope);
else
virtualMethods.Add(scope);
virtualMethods.add(scope);
}
prepareRenameVirtualProperties(propMethods);
prepareRenameVirtualEvents(eventMethods);
prepareRenameVirtualMethods(virtualMethods, "vmethod_", false);
prepareRenameVirtualMethods(ifaceMethods, "imethod_", false);
prepareRenameVirtualMethods(virtualMethods, "vmethod_", true);
prepareRenameVirtualMethods(ifaceMethods, "imethod_", true);
}
propMethods.visitAll((scope) => prepareRenameProperty(scope, false));
eventMethods.visitAll((scope) => prepareRenameEvent(scope, false));
virtualMethods.visitAll((scope) => prepareRenameVirtualMethods(scope, "vmethod_", false));
ifaceMethods.visitAll((scope) => prepareRenameVirtualMethods(scope, "imethod_", false));
Dictionary<TypeDef, int> numBaseClassesDict = new Dictionary<TypeDef, int>();
int getNumberOfBaseClasses(TypeDef type) {
int numBaseClasses;
if (numBaseClassesDict.TryGetValue(type, out numBaseClasses))
return numBaseClasses;
return numBaseClassesDict[type] = getNumberOfBaseClassesInternal(type);
}
int getNumberOfBaseClassesInternal(TypeDef type) {
if (type.baseType == null)
return 0;
return getNumberOfBaseClasses(type.baseType.typeDef) + 1;
}
int compareTypes(TypeDef a, TypeDef b) {
int ac = getNumberOfBaseClasses(a);
int bc = getNumberOfBaseClasses(b);
if (ac < bc) return -1;
if (ac > bc) return 1;
return Utils.compareInt32(a.Index, b.Index);
}
void sortScopes(List<MethodNameScope> scopes) {
var scopeToType = new Dictionary<MethodNameScope, TypeDef>(scopes.Count);
foreach (var scope in scopes) {
TypeDef type = null;
foreach (var method in scope.Methods) {
var owner = method.Owner;
if (type == null || compareTypes(owner, type) < 0)
type = owner;
}
scopeToType[scope] = type;
}
scopes.Sort((a, b) => compareTypes(scopeToType[a], scopeToType[b]));
propMethods.visitAll((scope) => prepareRenameProperty(scope, true));
eventMethods.visitAll((scope) => prepareRenameEvent(scope, true));
virtualMethods.visitAll((scope) => prepareRenameVirtualMethods(scope, "vmethod_", true));
ifaceMethods.visitAll((scope) => prepareRenameVirtualMethods(scope, "imethod_", true));
}
static readonly Regex removeGenericsArityRegex = new Regex(@"`[0-9]+");
@ -719,15 +740,6 @@ namespace de4dot.renamer {
return name.Substring(index + 1);
}
void prepareRenameVirtualEvents(List<MethodNameScope> scopes) {
sortScopes(scopes);
foreach (var scope in scopes)
prepareRenameEvent(scope, false);
foreach (var scope in scopes)
prepareRenameEvent(scope, true);
}
void prepareRenameEvent(MethodNameScope scope, bool renameOverrides) {
string methodPrefix, overridePrefix;
var eventName = prepareRenameEvent(scope, renameOverrides, out overridePrefix, out methodPrefix);
@ -808,15 +820,6 @@ namespace de4dot.renamer {
return null;
}
void prepareRenameVirtualProperties(List<MethodNameScope> scopes) {
sortScopes(scopes);
foreach (var scope in scopes)
prepareRenameProperty(scope, false);
foreach (var scope in scopes)
prepareRenameProperty(scope, true);
}
void prepareRenameProperty(MethodNameScope scope, bool renameOverrides) {
string overridePrefix;
var propName = prepareRenameProperty(scope, renameOverrides, out overridePrefix);
@ -918,16 +921,15 @@ namespace de4dot.renamer {
const string defaultVal = "Prop_";
var propType = getPropertyType(scope);
if (propType == null)
if (propType == null || propType is GenericInstanceType)
return defaultVal;
string name = propType.Name;
int i = name.IndexOf('`');
if (i >= 0)
name = name.Substring(0, i);
i = name.IndexOf('.');
if (i >= 0)
int i;
if ((i = name.IndexOf('`')) >= 0)
name = name.Substring(0, i);
if ((i = name.LastIndexOf('.')) >= 0)
name = name.Substring(i + 1);
if (name == "")
return defaultVal;
return name + "_";
@ -968,13 +970,6 @@ namespace de4dot.renamer {
return type;
}
void prepareRenameVirtualMethods(List<MethodNameScope> scopes, string namePrefix, bool renameOverrides) {
sortScopes(scopes);
foreach (var scope in scopes)
prepareRenameVirtualMethods(scope, namePrefix, renameOverrides);
}
void prepareRenameVirtualMethods(MethodNameScope scope, string namePrefix, bool renameOverrides) {
if (!hasInvalidMethodName(scope))
return;

View File

@ -29,7 +29,7 @@ namespace de4dot.renamer {
class TypeInfo : MemberInfo {
public string oldNamespace;
public string newNamespace;
public VariableNameState variableNameState;
public VariableNameState variableNameState = new VariableNameState();
public TypeDef type;
MemberInfos memberInfos;
@ -111,9 +111,24 @@ namespace de4dot.renamer {
prepareRenameGenericParams(type.GenericParams, checker);
}
public void mergeState() {
foreach (var ifaceInfo in type.interfaces)
mergeState(ifaceInfo.typeDef);
if (type.baseType != null)
mergeState(type.baseType.typeDef);
}
void mergeState(TypeDef other) {
if (other == null)
return;
TypeInfo otherInfo;
if (!memberInfos.tryGetType(other, out otherInfo))
return;
variableNameState.merge(otherInfo.variableNameState);
}
public void prepareRenameMembers() {
if (variableNameState == null)
variableNameState = memberInfos.type(type.baseType.typeDef).variableNameState.clone();
mergeState();
foreach (var fieldDef in type.AllFields)
variableNameState.addFieldName(field(fieldDef).oldName);

View File

@ -23,10 +23,56 @@ using Mono.Cecil;
namespace de4dot.renamer {
abstract class TypeNames {
protected IDictionary<string, INameCreator> typeNames = new Dictionary<string, INameCreator>(StringComparer.Ordinal);
protected INameCreator genericParamNameCreator = new NameCreator("gparam_");
protected Dictionary<string, NameCreator> typeNames = new Dictionary<string, NameCreator>(StringComparer.Ordinal);
protected NameCreator genericParamNameCreator = new NameCreator("gparam_");
public TypeNames() {
public string create(TypeReference typeRef) {
var elementType = typeRef.GetElementType();
if (elementType is GenericParameter)
return genericParamNameCreator.create();
var name = elementType.FullName;
NameCreator nc;
if (typeNames.TryGetValue(name, out nc))
return nc.create();
var parts = name.Replace('/', '.').Split(new char[] { '.' });
var newName = parts[parts.Length - 1];
int tickIndex = newName.LastIndexOf('`');
if (tickIndex > 0)
newName = newName.Substring(0, tickIndex);
return addTypeName(name, newName).create();
}
protected INameCreator addTypeName(string fullName, string newName) {
newName = fixName(newName);
var name2 = " " + newName;
NameCreator nc;
if (!typeNames.TryGetValue(name2, out nc))
typeNames[name2] = nc = new NameCreator(newName + "_");
typeNames[fullName] = nc;
return nc;
}
protected abstract string fixName(string name);
public virtual TypeNames merge(TypeNames other) {
foreach (var pair in other.typeNames) {
if (typeNames.ContainsKey(pair.Key))
typeNames[pair.Key].merge(pair.Value);
else
typeNames[pair.Key] = pair.Value.clone();
}
genericParamNameCreator.merge(other.genericParamNameCreator);
return this;
}
}
class VariableNameCreator : TypeNames {
public VariableNameCreator() {
addTypeName("System.Boolean", "bool");
addTypeName("System.Byte", "byte");
addTypeName("System.Char", "char");
@ -45,49 +91,6 @@ namespace de4dot.renamer {
addTypeName("System.Decimal", "decimal");
}
public string create(TypeReference typeRef) {
var elementType = typeRef.GetElementType();
if (elementType is GenericParameter)
return genericParamNameCreator.create();
var name = elementType.FullName;
INameCreator nc;
if (typeNames.TryGetValue(name, out nc))
return nc.create();
var parts = name.Replace('/', '.').Split(new char[] { '.' });
var newName = parts[parts.Length - 1];
int tickIndex = newName.LastIndexOf('`');
if (tickIndex > 0)
newName = newName.Substring(0, tickIndex);
return addTypeName(name, newName).create();
}
INameCreator addTypeName(string fullName, string newName) {
newName = fixName(newName);
var name2 = " " + newName;
INameCreator nc;
if (!typeNames.TryGetValue(name2, out nc))
typeNames[name2] = nc = new NameCreator(newName + "_");
typeNames[fullName] = nc;
return nc;
}
protected abstract string fixName(string name);
public abstract TypeNames clone();
protected IDictionary<string, INameCreator> cloneDict() {
var rv = new Dictionary<string, INameCreator>(StringComparer.Ordinal);
foreach (var key in typeNames.Keys)
rv[key] = typeNames[key].clone();
return rv;
}
}
class VariableNameCreator : TypeNames {
protected override string fixName(string name) {
// Make all leading upper case chars lower case
var s = "";
@ -99,25 +102,11 @@ namespace de4dot.renamer {
}
return s;
}
public override TypeNames clone() {
var rv = new VariableNameCreator();
rv.typeNames = cloneDict();
rv.genericParamNameCreator = genericParamNameCreator.clone();
return rv;
}
}
class PropertyNameCreator : TypeNames {
protected override string fixName(string name) {
return name.Substring(0, 1).ToUpperInvariant() + name.Substring(1);
}
public override TypeNames clone() {
var rv = new PropertyNameCreator();
rv.typeNames = cloneDict();
rv.genericParamNameCreator = genericParamNameCreator.clone();
return rv;
}
}
}

View File

@ -24,14 +24,14 @@ namespace de4dot.renamer {
class TypeRenamerState {
ExistingNames existingNames;
Dictionary<string, string> namespaceToNewName;
INameCreator createNamespaceName;
NameCreator createNamespaceName;
public ITypeNameCreator globalTypeNameCreator;
public ITypeNameCreator internalTypeNameCreator;
public TypeRenamerState() {
existingNames = new ExistingNames();
namespaceToNewName = new Dictionary<string, string>(StringComparer.Ordinal);
createNamespaceName = new GlobalNameCreator(new NameCreator("ns"));
createNamespaceName = new NameCreator("ns");
globalTypeNameCreator = new GlobalTypeNameCreator(existingNames);
internalTypeNameCreator = new TypeNameCreator(existingNames);
}

View File

@ -27,28 +27,27 @@ namespace de4dot.renamer {
ExistingNames existingEventNames = new ExistingNames();
TypeNames variableNameCreator = new VariableNameCreator(); // For fields and method args
TypeNames propertyNameCreator = new PropertyNameCreator();
INameCreator eventNameCreator = new NameCreator("Event_");
INameCreator genericPropertyNameCreator = new NameCreator("Prop_");
public INameCreator staticMethodNameCreator = new NameCreator("smethod_");
public INameCreator instanceMethodNameCreator = new NameCreator("method_");
NameCreator eventNameCreator = new NameCreator("Event_");
NameCreator genericPropertyNameCreator = new NameCreator("Prop_");
public NameCreator staticMethodNameCreator = new NameCreator("smethod_");
public NameCreator instanceMethodNameCreator = new NameCreator("method_");
public virtual VariableNameState clone() {
var rv = new VariableNameState();
cloneInit(rv);
return rv;
public VariableNameState clone() {
return new VariableNameState().merge(this);
}
void cloneInit(VariableNameState variableNameState) {
variableNameState.existingVariableNames = existingVariableNames.clone();
variableNameState.existingMethodNames = existingMethodNames.clone();
variableNameState.existingPropertyNames = existingPropertyNames.clone();
variableNameState.existingEventNames = existingEventNames.clone();
variableNameState.variableNameCreator = variableNameCreator.clone();
variableNameState.propertyNameCreator = propertyNameCreator.clone();
variableNameState.eventNameCreator = eventNameCreator.clone();
variableNameState.genericPropertyNameCreator = genericPropertyNameCreator.clone();
variableNameState.staticMethodNameCreator = staticMethodNameCreator.clone();
variableNameState.instanceMethodNameCreator = instanceMethodNameCreator.clone();
public VariableNameState merge(VariableNameState other) {
existingVariableNames.merge(other.existingVariableNames);
existingMethodNames.merge(other.existingMethodNames);
existingPropertyNames.merge(other.existingPropertyNames);
existingEventNames.merge(other.existingEventNames);
variableNameCreator.merge(other.variableNameCreator);
propertyNameCreator.merge(other.propertyNameCreator);
eventNameCreator.merge(other.eventNameCreator);
genericPropertyNameCreator.merge(other.genericPropertyNameCreator);
staticMethodNameCreator.merge(other.staticMethodNameCreator);
instanceMethodNameCreator.merge(other.instanceMethodNameCreator);
return this;
}
public string getNewPropertyName(PropertyDefinition propertyDefinition) {

View File

@ -68,8 +68,11 @@ namespace de4dot.renamer.asmmodules {
public bool hasEventMethod() {
foreach (var method in methods) {
if (method.Event != null)
return true;
if (method.Event != null) {
var evt = method.Event;
if (method == evt.AddMethod || method == evt.RemoveMethod || method == evt.RaiseMethod)
return true;
}
}
return false;
}
@ -82,14 +85,6 @@ namespace de4dot.renamer.asmmodules {
return false;
}
public bool hasEvent() {
foreach (var method in methods) {
if (method.Event != null)
return true;
}
return false;
}
public override string ToString() {
return string.Format("{0} -- {1}", methods.Count, methods.Count > 0 ? methods[0].ToString() : "");
}