summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java
blob: 37a70148484305479893b271d60b02439160b478 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*******************************************************************************
 * Copyright (c) 2015 Jeff Martin.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public
 * License v3.0 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl.html
 * <p>
 * Contributors:
 * Jeff Martin - initial API and implementation
 ******************************************************************************/

package cuchaz.enigma.translation.representation;

import com.google.common.collect.Lists;
import cuchaz.enigma.translation.Translatable;
import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.mapping.EntryMapping;
import cuchaz.enigma.translation.mapping.EntryResolver;
import cuchaz.enigma.translation.mapping.EntryMap;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.utils.Utils;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class MethodDescriptor implements Translatable {

	private List<TypeDescriptor> argumentDescs;
	private TypeDescriptor returnDesc;

	public MethodDescriptor(String desc) {
		try {
			this.argumentDescs = Lists.newArrayList();
			int i = 0;
			while (i < desc.length()) {
				char c = desc.charAt(i);
				if (c == '(') {
					assert (this.argumentDescs.isEmpty());
					assert (this.returnDesc == null);
					i++;
				} else if (c == ')') {
					i++;
					break;
				} else {
					String type = TypeDescriptor.parseFirst(desc.substring(i));
					this.argumentDescs.add(new TypeDescriptor(type));
					i += type.length();
				}
			}
			this.returnDesc = new TypeDescriptor(TypeDescriptor.parseFirst(desc.substring(i)));
		} catch (Exception ex) {
			throw new IllegalArgumentException("Unable to parse method descriptor: " + desc, ex);
		}
	}

	public MethodDescriptor(List<TypeDescriptor> argumentDescs, TypeDescriptor returnDesc) {
		this.argumentDescs = argumentDescs;
		this.returnDesc = returnDesc;
	}

	public List<TypeDescriptor> getArgumentDescs() {
		return this.argumentDescs;
	}

	public TypeDescriptor getReturnDesc() {
		return this.returnDesc;
	}

	@Override
	public String toString() {
		StringBuilder buf = new StringBuilder();
		buf.append("(");
		for (TypeDescriptor desc : this.argumentDescs) {
			buf.append(desc);
		}
		buf.append(")");
		buf.append(this.returnDesc);
		return buf.toString();
	}

	public Iterable<TypeDescriptor> types() {
		List<TypeDescriptor> descs = Lists.newArrayList();
		descs.addAll(this.argumentDescs);
		descs.add(this.returnDesc);
		return descs;
	}

	@Override
	public boolean equals(Object other) {
		return other instanceof MethodDescriptor && equals((MethodDescriptor) other);
	}

	public boolean equals(MethodDescriptor other) {
		return this.argumentDescs.equals(other.argumentDescs) && this.returnDesc.equals(other.returnDesc);
	}

	@Override
	public int hashCode() {
		return Utils.combineHashesOrdered(this.argumentDescs.hashCode(), this.returnDesc.hashCode());
	}

	public boolean hasClass(ClassEntry classEntry) {
		for (TypeDescriptor desc : types()) {
			if (desc.containsType() && desc.getTypeEntry().equals(classEntry)) {
				return true;
			}
		}
		return false;
	}

	public MethodDescriptor remap(Function<String, String> remapper) {
		List<TypeDescriptor> argumentDescs = new ArrayList<>(this.argumentDescs.size());
		for (TypeDescriptor desc : this.argumentDescs) {
			argumentDescs.add(desc.remap(remapper));
		}
		return new MethodDescriptor(argumentDescs, returnDesc.remap(remapper));
	}

	@Override
	public MethodDescriptor translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
		List<TypeDescriptor> translatedArguments = new ArrayList<>(argumentDescs.size());
		for (TypeDescriptor argument : argumentDescs) {
			translatedArguments.add(translator.translate(argument));
		}
		return new MethodDescriptor(translatedArguments, translator.translate(returnDesc));
	}

	public boolean canConflictWith(MethodDescriptor descriptor) {
		return descriptor.argumentDescs.equals(argumentDescs);
	}
}