summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java
blob: e1903d9f06616f056b83d0e34540e0bb5a70f2d7 (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
package cuchaz.enigma.analysis.index;

import com.google.common.collect.Maps;
import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.mapping.EntryResolver;
import cuchaz.enigma.translation.representation.AccessFlags;
import cuchaz.enigma.translation.representation.entry.MethodEntry;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Map;

public class BridgeMethodIndex implements JarIndexer, RemappableIndex {
	private final EntryIndex entryIndex;
	private final ReferenceIndex referenceIndex;

	private Map<MethodEntry, MethodEntry> accessedToBridge = Maps.newHashMap();

	public BridgeMethodIndex(EntryIndex entryIndex, ReferenceIndex referenceIndex) {
		this.entryIndex = entryIndex;
		this.referenceIndex = referenceIndex;
	}

	@Override
	public void remap(Translator translator) {
		accessedToBridge = translator.translate(accessedToBridge);
	}

	@Override
	public BridgeMethodIndex remapped(Translator translator) {
		BridgeMethodIndex index = new BridgeMethodIndex(entryIndex, referenceIndex);
		index.accessedToBridge = translator.translate(accessedToBridge);

		return index;
	}

	@Override
	public void processIndex(EntryResolver resolver) {
		// look for access and bridged methods
		for (MethodEntry methodEntry : entryIndex.getMethods()) {
			AccessFlags access = entryIndex.getMethodAccess(methodEntry);
			if (access == null || !access.isSynthetic()) {
				continue;
			}

			indexSyntheticMethod(methodEntry, access);
		}
	}

	private void indexSyntheticMethod(MethodEntry syntheticMethod, AccessFlags access) {
		if (access.isBridge()) {
			MethodEntry accessedMethod = findAccessMethod(syntheticMethod);
			if (accessedMethod != null) {
				accessedToBridge.put(accessedMethod, syntheticMethod);
			}
		}
	}

	private MethodEntry findAccessMethod(MethodEntry method) {
		// we want to find all compiler-added methods that directly call another with no processing

		// get all the methods that we call
		final Collection<MethodEntry> referencedMethods = referenceIndex.getMethodsReferencedBy(method);

		// is there just one?
		if (referencedMethods.size() != 1) {
			return null;
		}

		return referencedMethods.stream().findFirst().orElse(null);
	}

	@Nullable
	public MethodEntry getBridgeFromAccessed(MethodEntry entry) {
		return accessedToBridge.get(entry);
	}
}