summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar gegy10002019-02-23 19:42:00 +0200
committerGravatar gegy10002019-02-23 19:42:00 +0200
commitbb20ce047a2e20866b9532c441c7433b1973ba5b (patch)
treeed9f5bd596e43a1fffeef0b174c5370c039a9b62 /src
parentTweak inheritance and implementation tree generation (diff)
downloadenigma-bb20ce047a2e20866b9532c441c7433b1973ba5b.tar.gz
enigma-bb20ce047a2e20866b9532c441c7433b1973ba5b.tar.xz
enigma-bb20ce047a2e20866b9532c441c7433b1973ba5b.zip
Fix #110 and remap indices with matched bridge method names
Diffstat (limited to 'src')
-rw-r--r--src/main/java/cuchaz/enigma/CommandMain.java4
-rw-r--r--src/main/java/cuchaz/enigma/Deobfuscator.java12
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java30
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java12
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/JarIndex.java15
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java3
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java47
-rw-r--r--src/main/java/cuchaz/enigma/gui/GuiController.java23
-rw-r--r--src/main/java/cuchaz/enigma/gui/elements/MenuBar.java21
-rw-r--r--src/main/java/cuchaz/enigma/translation/Translator.java7
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java4
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java17
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java7
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java2
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java34
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java17
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java19
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java25
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java4
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java3
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java13
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java46
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTree.java5
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java4
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java29
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java5
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java12
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java2
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java5
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java5
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java5
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java5
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java5
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java5
-rw-r--r--src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java3
35 files changed, 289 insertions, 166 deletions
diff --git a/src/main/java/cuchaz/enigma/CommandMain.java b/src/main/java/cuchaz/enigma/CommandMain.java
index 7c0a3d53..c9f83828 100644
--- a/src/main/java/cuchaz/enigma/CommandMain.java
+++ b/src/main/java/cuchaz/enigma/CommandMain.java
@@ -74,7 +74,7 @@ public class CommandMain {
74 Deobfuscator deobfuscator = new Deobfuscator(jar); 74 Deobfuscator deobfuscator = new Deobfuscator(jar);
75 if (fileMappings != null) { 75 if (fileMappings != null) {
76 System.out.println("Reading mappings..."); 76 System.out.println("Reading mappings...");
77 EntryTree<EntryMapping> mappings = chooseEnigmaFormat(fileMappings).read(fileMappings); 77 EntryTree<EntryMapping> mappings = chooseEnigmaFormat(fileMappings).read(fileMappings, new ConsoleProgressListener());
78 deobfuscator.setMappings(mappings); 78 deobfuscator.setMappings(mappings);
79 } 79 }
80 return deobfuscator; 80 return deobfuscator;
@@ -94,7 +94,7 @@ public class CommandMain {
94 System.out.println("Reading mappings..."); 94 System.out.println("Reading mappings...");
95 95
96 MappingFormat readFormat = chooseEnigmaFormat(fileMappings); 96 MappingFormat readFormat = chooseEnigmaFormat(fileMappings);
97 EntryTree<EntryMapping> mappings = readFormat.read(fileMappings); 97 EntryTree<EntryMapping> mappings = readFormat.read(fileMappings, new ConsoleProgressListener());
98 System.out.println("Saving new mappings..."); 98 System.out.println("Saving new mappings...");
99 99
100 saveFormat.write(mappings, result.toPath(), new ConsoleProgressListener()); 100 saveFormat.write(mappings, result.toPath(), new ConsoleProgressListener());
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java
index 47cd05ce..b4736d8f 100644
--- a/src/main/java/cuchaz/enigma/Deobfuscator.java
+++ b/src/main/java/cuchaz/enigma/Deobfuscator.java
@@ -126,23 +126,27 @@ public class Deobfuscator {
126 } 126 }
127 127
128 public void setMappings(EntryTree<EntryMapping> mappings) { 128 public void setMappings(EntryTree<EntryMapping> mappings) {
129 setMappings(mappings, ProgressListener.VOID);
130 }
131
132 public void setMappings(EntryTree<EntryMapping> mappings, ProgressListener progress) {
129 if (mappings != null) { 133 if (mappings != null) {
130 Collection<Entry<?>> dropped = dropMappings(mappings); 134 Collection<Entry<?>> dropped = dropMappings(mappings, progress);
131 mapper = new EntryRemapper(jarIndex, mappings); 135 mapper = new EntryRemapper(jarIndex, mappings);
132 136
133 DeltaTrackingTree<EntryMapping> obfToDeobf = mapper.getObfToDeobf(); 137 DeltaTrackingTree<EntryMapping> obfToDeobf = mapper.getObfToDeobf();
134 for (Entry<?> entry : dropped) { 138 for (Entry<?> entry : dropped) {
135 obfToDeobf.trackDeletion(entry); 139 obfToDeobf.trackChange(entry);
136 } 140 }
137 } else { 141 } else {
138 mapper = new EntryRemapper(jarIndex); 142 mapper = new EntryRemapper(jarIndex);
139 } 143 }
140 } 144 }
141 145
142 private Collection<Entry<?>> dropMappings(EntryTree<EntryMapping> mappings) { 146 private Collection<Entry<?>> dropMappings(EntryTree<EntryMapping> mappings, ProgressListener progress) {
143 // drop mappings that don't match the jar 147 // drop mappings that don't match the jar
144 MappingsChecker checker = new MappingsChecker(jarIndex, mappings); 148 MappingsChecker checker = new MappingsChecker(jarIndex, mappings);
145 MappingsChecker.Dropped dropped = checker.dropBrokenMappings(); 149 MappingsChecker.Dropped dropped = checker.dropBrokenMappings(progress);
146 150
147 Map<Entry<?>, String> droppedMappings = dropped.getDroppedMappings(); 151 Map<Entry<?>, String> droppedMappings = dropped.getDroppedMappings();
148 for (Map.Entry<Entry<?>, String> mapping : droppedMappings.entrySet()) { 152 for (Map.Entry<Entry<?>, String> mapping : droppedMappings.entrySet()) {
diff --git a/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java b/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java
index de2ba1e5..649ce254 100644
--- a/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java
@@ -2,7 +2,6 @@ package cuchaz.enigma.analysis.index;
2 2
3import com.google.common.collect.Maps; 3import com.google.common.collect.Maps;
4import com.google.common.collect.Sets; 4import com.google.common.collect.Sets;
5import cuchaz.enigma.translation.mapping.EntryResolver;
6import cuchaz.enigma.translation.representation.AccessFlags; 5import cuchaz.enigma.translation.representation.AccessFlags;
7import cuchaz.enigma.translation.representation.MethodDescriptor; 6import cuchaz.enigma.translation.representation.MethodDescriptor;
8import cuchaz.enigma.translation.representation.TypeDescriptor; 7import cuchaz.enigma.translation.representation.TypeDescriptor;
@@ -11,10 +10,7 @@ import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
11import cuchaz.enigma.translation.representation.entry.MethodEntry; 10import cuchaz.enigma.translation.representation.entry.MethodEntry;
12 11
13import javax.annotation.Nullable; 12import javax.annotation.Nullable;
14import java.util.Collection; 13import java.util.*;
15import java.util.List;
16import java.util.Map;
17import java.util.Set;
18 14
19public class BridgeMethodIndex implements JarIndexer { 15public class BridgeMethodIndex implements JarIndexer {
20 private final EntryIndex entryIndex; 16 private final EntryIndex entryIndex;
@@ -30,8 +26,7 @@ public class BridgeMethodIndex implements JarIndexer {
30 this.referenceIndex = referenceIndex; 26 this.referenceIndex = referenceIndex;
31 } 27 }
32 28
33 @Override 29 public void findBridgeMethods() {
34 public void processIndex(EntryResolver resolver) {
35 // look for access and bridged methods 30 // look for access and bridged methods
36 for (MethodEntry methodEntry : entryIndex.getMethods()) { 31 for (MethodEntry methodEntry : entryIndex.getMethods()) {
37 MethodDefEntry methodDefEntry = (MethodDefEntry) methodEntry; 32 MethodDefEntry methodDefEntry = (MethodDefEntry) methodEntry;
@@ -45,6 +40,23 @@ public class BridgeMethodIndex implements JarIndexer {
45 } 40 }
46 } 41 }
47 42
43 @Override
44 public void processIndex(JarIndex index) {
45 Map<MethodEntry, MethodEntry> copiedAccessToBridge = new HashMap<>(accessedToBridge);
46
47 for (Map.Entry<MethodEntry, MethodEntry> entry : copiedAccessToBridge.entrySet()) {
48 MethodEntry accessedEntry = entry.getKey();
49 MethodEntry bridgeEntry = entry.getValue();
50 if (bridgeEntry.getName().equals(accessedEntry.getName())) {
51 continue;
52 }
53
54 MethodEntry renamedAccessedEntry = accessedEntry.withName(bridgeEntry.getName());
55 bridgeMethods.add(renamedAccessedEntry);
56 accessedToBridge.put(renamedAccessedEntry, accessedToBridge.get(accessedEntry));
57 }
58 }
59
48 private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) { 60 private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) {
49 MethodEntry accessedMethod = findAccessMethod(syntheticMethod); 61 MethodEntry accessedMethod = findAccessMethod(syntheticMethod);
50 if (accessedMethod == null) { 62 if (accessedMethod == null) {
@@ -129,4 +141,8 @@ public class BridgeMethodIndex implements JarIndexer {
129 public MethodEntry getBridgeFromAccessed(MethodEntry entry) { 141 public MethodEntry getBridgeFromAccessed(MethodEntry entry) {
130 return accessedToBridge.get(entry); 142 return accessedToBridge.get(entry);
131 } 143 }
144
145 public Map<MethodEntry, MethodEntry> getAccessedToBridge() {
146 return Collections.unmodifiableMap(accessedToBridge);
147 }
132} 148}
diff --git a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java b/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java
index 773eaf18..645110a7 100644
--- a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java
@@ -28,6 +28,18 @@ public class EntryIndex implements JarIndexer {
28 fields.put(fieldEntry, fieldEntry.getAccess()); 28 fields.put(fieldEntry, fieldEntry.getAccess());
29 } 29 }
30 30
31 @Override
32 public void processIndex(JarIndex index) {
33 Map<MethodEntry, MethodEntry> accessedToBridge = index.getBridgeMethodIndex().getAccessedToBridge();
34 for (Map.Entry<MethodEntry, MethodEntry> entry : accessedToBridge.entrySet()) {
35 MethodEntry accessedEntry = entry.getKey();
36 MethodEntry bridgeEntry = entry.getValue();
37
38 MethodEntry renamedAccessedEntry = accessedEntry.withName(bridgeEntry.getName());
39 methods.put(renamedAccessedEntry, methods.remove(accessedEntry));
40 }
41 }
42
31 public boolean hasClass(ClassEntry entry) { 43 public boolean hasClass(ClassEntry entry) {
32 return classes.containsKey(entry); 44 return classes.containsKey(entry);
33 } 45 }
diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
index cb58fced..a429ff6e 100644
--- a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
@@ -53,19 +53,22 @@ public class JarIndex implements JarIndexer {
53 } 53 }
54 54
55 public void indexJar(ParsedJar jar, Consumer<String> progress) { 55 public void indexJar(ParsedJar jar, Consumer<String> progress) {
56 progress.accept("Indexing entries (1/3)"); 56 progress.accept("Indexing entries (1/4)");
57 jar.visitReader(name -> new IndexClassVisitor(this, Opcodes.ASM5), ClassReader.SKIP_CODE); 57 jar.visitReader(name -> new IndexClassVisitor(this, Opcodes.ASM5), ClassReader.SKIP_CODE);
58 58
59 progress.accept("Indexing entry references (2/3)"); 59 progress.accept("Indexing entry references (2/4)");
60 jar.visitReader(name -> new IndexReferenceVisitor(this, Opcodes.ASM5), ClassReader.SKIP_FRAMES); 60 jar.visitReader(name -> new IndexReferenceVisitor(this, Opcodes.ASM5), ClassReader.SKIP_FRAMES);
61 61
62 progress.accept("Processing index (3/3)"); 62 progress.accept("Finding bridge methods (3/4)");
63 processIndex(entryResolver); 63 bridgeMethodIndex.findBridgeMethods();
64
65 progress.accept("Processing index (4/4)");
66 processIndex(this);
64 } 67 }
65 68
66 @Override 69 @Override
67 public void processIndex(EntryResolver resolver) { 70 public void processIndex(JarIndex index) {
68 indexers.forEach(indexer -> indexer.processIndex(entryResolver)); 71 indexers.forEach(indexer -> indexer.processIndex(index));
69 } 72 }
70 73
71 @Override 74 @Override
diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java
index a087e598..457c2237 100644
--- a/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java
+++ b/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java
@@ -1,6 +1,5 @@
1package cuchaz.enigma.analysis.index; 1package cuchaz.enigma.analysis.index;
2 2
3import cuchaz.enigma.translation.mapping.EntryResolver;
4import cuchaz.enigma.translation.representation.entry.*; 3import cuchaz.enigma.translation.representation.entry.*;
5 4
6public interface JarIndexer { 5public interface JarIndexer {
@@ -19,6 +18,6 @@ public interface JarIndexer {
19 default void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry) { 18 default void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry) {
20 } 19 }
21 20
22 default void processIndex(EntryResolver resolver) { 21 default void processIndex(JarIndex index) {
23 } 22 }
24} 23}
diff --git a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java b/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java
index ac11da46..ee28b3e7 100644
--- a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java
@@ -3,12 +3,12 @@ package cuchaz.enigma.analysis.index;
3import com.google.common.collect.HashMultimap; 3import com.google.common.collect.HashMultimap;
4import com.google.common.collect.Multimap; 4import com.google.common.collect.Multimap;
5import cuchaz.enigma.analysis.EntryReference; 5import cuchaz.enigma.analysis.EntryReference;
6import cuchaz.enigma.translation.mapping.EntryResolver;
7import cuchaz.enigma.translation.mapping.ResolutionStrategy; 6import cuchaz.enigma.translation.mapping.ResolutionStrategy;
8import cuchaz.enigma.translation.representation.entry.*; 7import cuchaz.enigma.translation.representation.entry.*;
9 8
10import java.util.Collection; 9import java.util.Collection;
11import java.util.Map; 10import java.util.Map;
11import java.util.Optional;
12 12
13public class ReferenceIndex implements JarIndexer { 13public class ReferenceIndex implements JarIndexer {
14 private Multimap<MethodEntry, MethodEntry> methodReferences = HashMultimap.create(); 14 private Multimap<MethodEntry, MethodEntry> methodReferences = HashMultimap.create();
@@ -34,35 +34,54 @@ public class ReferenceIndex implements JarIndexer {
34 } 34 }
35 35
36 @Override 36 @Override
37 public void processIndex(EntryResolver resolver) { 37 public void processIndex(JarIndex index) {
38 methodReferences = resolveReferences(resolver, methodReferences); 38 methodReferences = remapReferences(index, methodReferences);
39 referencesToMethods = resolveReferencesTo(resolver, referencesToMethods); 39 referencesToMethods = remapReferencesTo(index, referencesToMethods);
40 referencesToClasses = resolveReferencesTo(resolver, referencesToClasses); 40 referencesToClasses = remapReferencesTo(index, referencesToClasses);
41 referencesToFields = resolveReferencesTo(resolver, referencesToFields); 41 referencesToFields = remapReferencesTo(index, referencesToFields);
42 } 42 }
43 43
44 private <K extends Entry<?>, V extends Entry<?>> Multimap<K, V> resolveReferences(EntryResolver resolver, Multimap<K, V> multimap) { 44 private <K extends Entry<?>, V extends Entry<?>> Multimap<K, V> remapReferences(JarIndex index, Multimap<K, V> multimap) {
45 Multimap<K, V> resolved = HashMultimap.create(); 45 Multimap<K, V> resolved = HashMultimap.create();
46 for (Map.Entry<K, V> entry : multimap.entries()) { 46 for (Map.Entry<K, V> entry : multimap.entries()) {
47 resolved.put(resolve(resolver, entry.getKey()), resolve(resolver, entry.getValue())); 47 resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue()));
48 } 48 }
49 return resolved; 49 return resolved;
50 } 50 }
51 51
52 private <E extends Entry<?>, C extends Entry<?>> Multimap<E, EntryReference<E, C>> resolveReferencesTo(EntryResolver resolver, Multimap<E, EntryReference<E, C>> multimap) { 52 private <E extends Entry<?>, C extends Entry<?>> Multimap<E, EntryReference<E, C>> remapReferencesTo(JarIndex index, Multimap<E, EntryReference<E, C>> multimap) {
53 Multimap<E, EntryReference<E, C>> resolved = HashMultimap.create(); 53 Multimap<E, EntryReference<E, C>> resolved = HashMultimap.create();
54 for (Map.Entry<E, EntryReference<E, C>> entry : multimap.entries()) { 54 for (Map.Entry<E, EntryReference<E, C>> entry : multimap.entries()) {
55 resolved.put(resolve(resolver, entry.getKey()), resolve(resolver, entry.getValue())); 55 resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue()));
56 } 56 }
57 return resolved; 57 return resolved;
58 } 58 }
59 59
60 private <E extends Entry<?>> E resolve(EntryResolver resolver, E entry) { 60 private <E extends Entry<?>> E remap(JarIndex index, E entry) {
61 return resolver.resolveFirstEntry(entry, ResolutionStrategy.RESOLVE_CLOSEST); 61 E resolvedEntry = index.getEntryResolver().resolveFirstEntry(entry, ResolutionStrategy.RESOLVE_CLOSEST);
62
63 Optional<E> remappedBridge = getRemappedBridge(index, resolvedEntry);
64 return remappedBridge.orElse(resolvedEntry);
65 }
66
67 private <E extends Entry<?>, C extends Entry<?>> EntryReference<E, C> remap(JarIndex index, EntryReference<E, C> reference) {
68 EntryReference<E, C> resolvedReference = index.getEntryResolver().resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST);
69
70 getRemappedBridge(index, resolvedReference.entry).ifPresent(e -> resolvedReference.entry = e);
71 getRemappedBridge(index, resolvedReference.context).ifPresent(e -> resolvedReference.context = e);
72
73 return resolvedReference;
62 } 74 }
63 75
64 private <E extends Entry<?>, C extends Entry<?>> EntryReference<E, C> resolve(EntryResolver resolver, EntryReference<E, C> reference) { 76 @SuppressWarnings("unchecked")
65 return resolver.resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST); 77 private <E extends Entry<?>> Optional<E> getRemappedBridge(JarIndex index, E entry) {
78 if (entry instanceof MethodEntry) {
79 MethodEntry bridgeEntry = index.getBridgeMethodIndex().getBridgeFromAccessed((MethodEntry) entry);
80 if (bridgeEntry != null) {
81 return Optional.of((E) entry.withName(bridgeEntry.getName()));
82 }
83 }
84 return Optional.empty();
66 } 85 }
67 86
68 public Collection<MethodEntry> getMethodsReferencedBy(MethodEntry entry) { 87 public Collection<MethodEntry> getMethodsReferencedBy(MethodEntry entry) {
diff --git a/src/main/java/cuchaz/enigma/gui/GuiController.java b/src/main/java/cuchaz/enigma/gui/GuiController.java
index 45c61319..15211e01 100644
--- a/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -32,6 +32,7 @@ import cuchaz.enigma.translation.representation.entry.MethodEntry;
32import cuchaz.enigma.utils.ReadableToken; 32import cuchaz.enigma.utils.ReadableToken;
33 33
34import javax.annotation.Nullable; 34import javax.annotation.Nullable;
35import javax.swing.*;
35import java.awt.event.ItemEvent; 36import java.awt.event.ItemEvent;
36import java.io.File; 37import java.io.File;
37import java.io.IOException; 38import java.io.IOException;
@@ -80,16 +81,22 @@ public class GuiController {
80 this.gui.onCloseJar(); 81 this.gui.onCloseJar();
81 } 82 }
82 83
83 public void openMappings(MappingFormat format, Path path) throws IOException, MappingParseException { 84 public void openMappings(MappingFormat format, Path path) {
84 EntryTree<EntryMapping> mappings = format.read(path); 85 ProgressDialog.runInThread(this.gui.getFrame(), progress -> {
85 deobfuscator.setMappings(mappings); 86 try {
87 EntryTree<EntryMapping> mappings = format.read(path, progress);
88 deobfuscator.setMappings(mappings, progress);
86 89
87 gui.setMappingsFile(path); 90 gui.setMappingsFile(path);
88 loadedMappingFormat = format; 91 loadedMappingFormat = format;
89 loadedMappingPath = path; 92 loadedMappingPath = path;
90 93
91 refreshClasses(); 94 refreshClasses();
92 refreshCurrentClass(); 95 refreshCurrentClass();
96 } catch (MappingParseException e) {
97 JOptionPane.showMessageDialog(this.gui.getFrame(), e.getMessage());
98 }
99 });
93 } 100 }
94 101
95 public void saveMappings(Path path) { 102 public void saveMappings(Path path) {
diff --git a/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java b/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
index 14ad53dc..d7be1a9d 100644
--- a/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
+++ b/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
@@ -5,7 +5,6 @@ import cuchaz.enigma.config.Themes;
5import cuchaz.enigma.gui.Gui; 5import cuchaz.enigma.gui.Gui;
6import cuchaz.enigma.gui.dialog.AboutDialog; 6import cuchaz.enigma.gui.dialog.AboutDialog;
7import cuchaz.enigma.gui.dialog.SearchDialog; 7import cuchaz.enigma.gui.dialog.SearchDialog;
8import cuchaz.enigma.throwables.MappingParseException;
9import cuchaz.enigma.translation.mapping.serde.MappingFormat; 8import cuchaz.enigma.translation.mapping.serde.MappingFormat;
10 9
11import javax.swing.*; 10import javax.swing.*;
@@ -68,15 +67,9 @@ public class MenuBar extends JMenuBar {
68 openMenu.add(item); 67 openMenu.add(item);
69 item.addActionListener(event -> { 68 item.addActionListener(event -> {
70 if (this.gui.enigmaMappingsFileChooser.showOpenDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) { 69 if (this.gui.enigmaMappingsFileChooser.showOpenDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) {
71 try { 70 File selectedFile = this.gui.enigmaMappingsFileChooser.getSelectedFile();
72 File selectedFile = this.gui.enigmaMappingsFileChooser.getSelectedFile(); 71 MappingFormat format = selectedFile.isDirectory() ? MappingFormat.ENIGMA_DIRECTORY : MappingFormat.ENIGMA_FILE;
73 MappingFormat format = selectedFile.isDirectory() ? MappingFormat.ENIGMA_DIRECTORY : MappingFormat.ENIGMA_FILE; 72 this.gui.getController().openMappings(format, selectedFile.toPath());
74 this.gui.getController().openMappings(format, selectedFile.toPath());
75 } catch (IOException ex) {
76 throw new Error(ex);
77 } catch (MappingParseException ex) {
78 JOptionPane.showMessageDialog(this.gui.getFrame(), ex.getMessage());
79 }
80 } 73 }
81 }); 74 });
82 this.openEnigmaMappingsMenu = item; 75 this.openEnigmaMappingsMenu = item;
@@ -87,13 +80,7 @@ public class MenuBar extends JMenuBar {
87 this.gui.tinyMappingsFileChooser.setVisible(true); 80 this.gui.tinyMappingsFileChooser.setVisible(true);
88 File file = new File(this.gui.tinyMappingsFileChooser.getDirectory() + File.separator + this.gui.tinyMappingsFileChooser.getFile()); 81 File file = new File(this.gui.tinyMappingsFileChooser.getDirectory() + File.separator + this.gui.tinyMappingsFileChooser.getFile());
89 if (file.exists()) { 82 if (file.exists()) {
90 try { 83 this.gui.getController().openMappings(MappingFormat.TINY_FILE, file.toPath());
91 this.gui.getController().openMappings(MappingFormat.TINY_FILE, file.toPath());
92 } catch (IOException ex) {
93 throw new Error(ex);
94 } catch (MappingParseException ex) {
95 JOptionPane.showMessageDialog(this.gui.getFrame(), ex.getMessage());
96 }
97 } 84 }
98 }); 85 });
99 this.openTinyMappingsMenu = item; 86 this.openTinyMappingsMenu = item;
diff --git a/src/main/java/cuchaz/enigma/translation/Translator.java b/src/main/java/cuchaz/enigma/translation/Translator.java
index de2003e8..c70141f2 100644
--- a/src/main/java/cuchaz/enigma/translation/Translator.java
+++ b/src/main/java/cuchaz/enigma/translation/Translator.java
@@ -17,6 +17,7 @@ import com.google.common.collect.Multimap;
17import java.util.Collection; 17import java.util.Collection;
18import java.util.HashMap; 18import java.util.HashMap;
19import java.util.Map; 19import java.util.Map;
20import java.util.Set;
20import java.util.stream.Collectors; 21import java.util.stream.Collectors;
21 22
22public interface Translator { 23public interface Translator {
@@ -28,6 +29,12 @@ public interface Translator {
28 .collect(Collectors.toList()); 29 .collect(Collectors.toList());
29 } 30 }
30 31
32 default <T extends Translatable> Set<T> translate(Set<T> translatable) {
33 return translatable.stream()
34 .map(this::translate)
35 .collect(Collectors.toSet());
36 }
37
31 default <T extends Translatable, V> Map<T, V> translateKeys(Map<T, V> translatable) { 38 default <T extends Translatable, V> Map<T, V> translateKeys(Map<T, V> translatable) {
32 Map<T, V> result = new HashMap<>(translatable.size()); 39 Map<T, V> result = new HashMap<>(translatable.size());
33 for (Map.Entry<T, V> entry : translatable.entrySet()) { 40 for (Map.Entry<T, V> entry : translatable.entrySet()) {
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java b/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java
index 6af48466..e1a32533 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java
@@ -3,7 +3,7 @@ package cuchaz.enigma.translation.mapping;
3import cuchaz.enigma.translation.representation.entry.Entry; 3import cuchaz.enigma.translation.representation.entry.Entry;
4 4
5import javax.annotation.Nullable; 5import javax.annotation.Nullable;
6import java.util.Collection; 6import java.util.stream.Stream;
7 7
8public interface EntryMap<T> { 8public interface EntryMap<T> {
9 void insert(Entry<?> entry, T value); 9 void insert(Entry<?> entry, T value);
@@ -18,7 +18,7 @@ public interface EntryMap<T> {
18 return get(entry) != null; 18 return get(entry) != null;
19 } 19 }
20 20
21 Collection<Entry<?>> getAllEntries(); 21 Stream<Entry<?>> getAllEntries();
22 22
23 boolean isEmpty(); 23 boolean isEmpty();
24} 24}
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java b/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java
index f11cdefb..b74cc0b3 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java
@@ -27,4 +27,21 @@ public class EntryMapping {
27 } 27 }
28 return accessModifier; 28 return accessModifier;
29 } 29 }
30
31 @Override
32 public boolean equals(Object obj) {
33 if (obj == this) return true;
34
35 if (obj instanceof EntryMapping) {
36 EntryMapping mapping = (EntryMapping) obj;
37 return mapping.targetName.equals(targetName) && mapping.accessModifier.equals(accessModifier);
38 }
39
40 return false;
41 }
42
43 @Override
44 public int hashCode() {
45 return targetName.hashCode() + accessModifier.hashCode() * 31;
46 }
30} 47}
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java b/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java
index fa421b9f..ed9f8202 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java
@@ -11,6 +11,7 @@ import cuchaz.enigma.translation.representation.entry.Entry;
11 11
12import javax.annotation.Nullable; 12import javax.annotation.Nullable;
13import java.util.Collection; 13import java.util.Collection;
14import java.util.stream.Stream;
14 15
15public class EntryRemapper { 16public class EntryRemapper {
16 private final DeltaTrackingTree<EntryMapping> obfToDeobf; 17 private final DeltaTrackingTree<EntryMapping> obfToDeobf;
@@ -69,14 +70,10 @@ public class EntryRemapper {
69 return deobfuscator; 70 return deobfuscator;
70 } 71 }
71 72
72 public Collection<Entry<?>> getObfEntries() { 73 public Stream<Entry<?>> getObfEntries() {
73 return obfToDeobf.getAllEntries(); 74 return obfToDeobf.getAllEntries();
74 } 75 }
75 76
76 public Collection<Entry<?>> getObfRootEntries() {
77 return obfToDeobf.getRootEntries();
78 }
79
80 public Collection<Entry<?>> getObfChildren(Entry<?> obfuscatedEntry) { 77 public Collection<Entry<?>> getObfChildren(Entry<?> obfuscatedEntry) {
81 return obfToDeobf.getChildren(obfuscatedEntry); 78 return obfToDeobf.getChildren(obfuscatedEntry);
82 } 79 }
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java b/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java
index 1f2290a0..6c8ed76d 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java
@@ -91,6 +91,8 @@ public class IndexEntryResolver implements EntryResolver {
91 Set<Entry<ClassEntry>> resolvedBridge = resolveChildEntry(bridgeMethod, strategy); 91 Set<Entry<ClassEntry>> resolvedBridge = resolveChildEntry(bridgeMethod, strategy);
92 if (!resolvedBridge.isEmpty()) { 92 if (!resolvedBridge.isEmpty()) {
93 return resolvedBridge; 93 return resolvedBridge;
94 } else {
95 return Collections.singleton(bridgeMethod);
94 } 96 }
95 } 97 }
96 } 98 }
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java b/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java
index 9f1f468b..1407bb60 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java
@@ -2,55 +2,53 @@ package cuchaz.enigma.translation.mapping;
2 2
3import cuchaz.enigma.translation.Translatable; 3import cuchaz.enigma.translation.Translatable;
4import cuchaz.enigma.translation.Translator; 4import cuchaz.enigma.translation.Translator;
5import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
6import cuchaz.enigma.translation.mapping.tree.EntryTree; 5import cuchaz.enigma.translation.mapping.tree.EntryTree;
6import cuchaz.enigma.translation.mapping.tree.EntryTreeNode;
7import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
7import cuchaz.enigma.translation.representation.entry.Entry; 8import cuchaz.enigma.translation.representation.entry.Entry;
8 9
10import java.util.stream.Stream;
11
9public class MappingDelta<T> implements Translatable { 12public class MappingDelta<T> implements Translatable {
10 public static final Object PLACEHOLDER = new Object(); 13 public static final Object PLACEHOLDER = new Object();
11 14
12 private final EntryTree<T> baseMappings; 15 private final EntryTree<T> baseMappings;
13 16
14 private final EntryTree<Object> additions; 17 private final EntryTree<Object> changes;
15 private final EntryTree<Object> deletions;
16 18
17 public MappingDelta(EntryTree<T> baseMappings, EntryTree<Object> additions, EntryTree<Object> deletions) { 19 public MappingDelta(EntryTree<T> baseMappings, EntryTree<Object> changes) {
18 this.baseMappings = baseMappings; 20 this.baseMappings = baseMappings;
19 this.additions = additions; 21 this.changes = changes;
20 this.deletions = deletions;
21 } 22 }
22 23
23 public MappingDelta(EntryTree<T> baseMappings) { 24 public MappingDelta(EntryTree<T> baseMappings) {
24 this(baseMappings, new HashEntryTree<>(), new HashEntryTree<>()); 25 this(baseMappings, new HashEntryTree<>());
25 } 26 }
26 27
27 public static <T> MappingDelta<T> added(EntryTree<T> mappings) { 28 public static <T> MappingDelta<T> added(EntryTree<T> mappings) {
28 EntryTree<Object> additions = new HashEntryTree<>(); 29 EntryTree<Object> changes = new HashEntryTree<>();
29 for (Entry<?> entry : mappings.getAllEntries()) { 30 mappings.getAllEntries().forEach(entry -> changes.insert(entry, PLACEHOLDER));
30 additions.insert(entry, PLACEHOLDER);
31 }
32 31
33 return new MappingDelta<>(new HashEntryTree<>(), additions, new HashEntryTree<>()); 32 return new MappingDelta<>(new HashEntryTree<>(), changes);
34 } 33 }
35 34
36 public EntryTree<T> getBaseMappings() { 35 public EntryTree<T> getBaseMappings() {
37 return baseMappings; 36 return baseMappings;
38 } 37 }
39 38
40 public EntryTree<?> getAdditions() { 39 public EntryTree<?> getChanges() {
41 return additions; 40 return changes;
42 } 41 }
43 42
44 public EntryTree<?> getDeletions() { 43 public Stream<Entry<?>> getChangedRoots() {
45 return deletions; 44 return changes.getRootNodes().map(EntryTreeNode::getEntry);
46 } 45 }
47 46
48 @Override 47 @Override
49 public MappingDelta<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { 48 public MappingDelta<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
50 return new MappingDelta<>( 49 return new MappingDelta<>(
51 translator.translate(baseMappings), 50 translator.translate(baseMappings),
52 translator.translate(additions), 51 translator.translate(changes)
53 translator.translate(deletions)
54 ); 52 );
55 } 53 }
56} 54}
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java b/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java
index 77d75ecb..af9e63a2 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java
@@ -11,6 +11,7 @@
11 11
12package cuchaz.enigma.translation.mapping; 12package cuchaz.enigma.translation.mapping;
13 13
14import cuchaz.enigma.ProgressListener;
14import cuchaz.enigma.analysis.index.JarIndex; 15import cuchaz.enigma.analysis.index.JarIndex;
15import cuchaz.enigma.translation.mapping.tree.EntryTree; 16import cuchaz.enigma.translation.mapping.tree.EntryTree;
16import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; 17import cuchaz.enigma.translation.mapping.tree.EntryTreeNode;
@@ -22,6 +23,7 @@ import cuchaz.enigma.translation.representation.entry.MethodEntry;
22import java.util.Collection; 23import java.util.Collection;
23import java.util.HashMap; 24import java.util.HashMap;
24import java.util.Map; 25import java.util.Map;
26import java.util.stream.Collectors;
25 27
26public class MappingsChecker { 28public class MappingsChecker {
27 private final JarIndex index; 29 private final JarIndex index;
@@ -32,14 +34,19 @@ public class MappingsChecker {
32 this.mappings = mappings; 34 this.mappings = mappings;
33 } 35 }
34 36
35 public Dropped dropBrokenMappings() { 37 public Dropped dropBrokenMappings(ProgressListener progress) {
36 Dropped dropped = new Dropped(); 38 Dropped dropped = new Dropped();
37 39
38 Collection<Entry<?>> obfEntries = mappings.getAllEntries(); 40 Collection<Entry<?>> obfEntries = mappings.getAllEntries()
41 .filter(e -> e instanceof ClassEntry || e instanceof MethodEntry || e instanceof FieldEntry)
42 .collect(Collectors.toList());
43
44 progress.init(obfEntries.size(), "Checking for dropped mappings");
45
46 int steps = 0;
39 for (Entry<?> entry : obfEntries) { 47 for (Entry<?> entry : obfEntries) {
40 if (entry instanceof ClassEntry || entry instanceof MethodEntry || entry instanceof FieldEntry) { 48 progress.step(steps++, entry.toString());
41 tryDropEntry(dropped, entry); 49 tryDropEntry(dropped, entry);
42 }
43 } 50 }
44 51
45 dropped.apply(mappings); 52 dropped.apply(mappings);
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java
index d36bc0bc..3f61325d 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java
@@ -1,12 +1,13 @@
1package cuchaz.enigma.translation.mapping.serde; 1package cuchaz.enigma.translation.mapping.serde;
2 2
3import com.google.common.base.Charsets; 3import com.google.common.base.Charsets;
4import cuchaz.enigma.ProgressListener;
4import cuchaz.enigma.throwables.MappingParseException; 5import cuchaz.enigma.throwables.MappingParseException;
5import cuchaz.enigma.translation.mapping.AccessModifier; 6import cuchaz.enigma.translation.mapping.AccessModifier;
6import cuchaz.enigma.translation.mapping.EntryMapping; 7import cuchaz.enigma.translation.mapping.EntryMapping;
7import cuchaz.enigma.translation.mapping.MappingPair; 8import cuchaz.enigma.translation.mapping.MappingPair;
8import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
9import cuchaz.enigma.translation.mapping.tree.EntryTree; 9import cuchaz.enigma.translation.mapping.tree.EntryTree;
10import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
10import cuchaz.enigma.translation.representation.MethodDescriptor; 11import cuchaz.enigma.translation.representation.MethodDescriptor;
11import cuchaz.enigma.translation.representation.TypeDescriptor; 12import cuchaz.enigma.translation.representation.TypeDescriptor;
12import cuchaz.enigma.translation.representation.entry.*; 13import cuchaz.enigma.translation.representation.entry.*;
@@ -24,22 +25,32 @@ import java.util.stream.Collectors;
24public enum EnigmaMappingsReader implements MappingsReader { 25public enum EnigmaMappingsReader implements MappingsReader {
25 FILE { 26 FILE {
26 @Override 27 @Override
27 public EntryTree<EntryMapping> read(Path path) throws IOException, MappingParseException { 28 public EntryTree<EntryMapping> read(Path path, ProgressListener progress) throws IOException, MappingParseException {
29 progress.init(1, "Loading mapping file");
30
28 EntryTree<EntryMapping> mappings = new HashEntryTree<>(); 31 EntryTree<EntryMapping> mappings = new HashEntryTree<>();
29 readFile(path, mappings); 32 readFile(path, mappings);
33
34 progress.step(1, "Done!");
35
30 return mappings; 36 return mappings;
31 } 37 }
32 }, 38 },
33 DIRECTORY { 39 DIRECTORY {
34 @Override 40 @Override
35 public EntryTree<EntryMapping> read(Path path) throws IOException, MappingParseException { 41 public EntryTree<EntryMapping> read(Path root, ProgressListener progress) throws IOException, MappingParseException {
36 EntryTree<EntryMapping> mappings = new HashEntryTree<>(); 42 EntryTree<EntryMapping> mappings = new HashEntryTree<>();
37 43
38 List<Path> files = Files.walk(path) 44 List<Path> files = Files.walk(root)
39 .filter(f -> !Files.isDirectory(f)) 45 .filter(f -> !Files.isDirectory(f))
40 .filter(f -> f.toString().endsWith(".mapping")) 46 .filter(f -> f.toString().endsWith(".mapping"))
41 .collect(Collectors.toList()); 47 .collect(Collectors.toList());
48
49 progress.init(files.size(), "Loading mapping files");
50 int step = 0;
51
42 for (Path file : files) { 52 for (Path file : files) {
53 progress.step(step++, root.relativize(file).toString());
43 if (Files.isHidden(file)) { 54 if (Files.isHidden(file)) {
44 continue; 55 continue;
45 } 56 }
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java
index 8c55fa99..618bb0a7 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java
@@ -28,6 +28,7 @@ import java.nio.file.Path;
28import java.nio.file.Paths; 28import java.nio.file.Paths;
29import java.util.ArrayList; 29import java.util.ArrayList;
30import java.util.Collection; 30import java.util.Collection;
31import java.util.Objects;
31import java.util.concurrent.atomic.AtomicInteger; 32import java.util.concurrent.atomic.AtomicInteger;
32import java.util.stream.Collectors; 33import java.util.stream.Collectors;
33 34
@@ -35,7 +36,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
35 FILE { 36 FILE {
36 @Override 37 @Override
37 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress) { 38 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress) {
38 Collection<ClassEntry> classes = mappings.getRootEntries().stream() 39 Collection<ClassEntry> classes = mappings.getRootNodes()
39 .filter(entry -> entry instanceof ClassEntry) 40 .filter(entry -> entry instanceof ClassEntry)
40 .map(entry -> (ClassEntry) entry) 41 .map(entry -> (ClassEntry) entry)
41 .collect(Collectors.toList()); 42 .collect(Collectors.toList());
@@ -56,19 +57,19 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
56 DIRECTORY { 57 DIRECTORY {
57 @Override 58 @Override
58 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress) { 59 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress) {
59 applyDeletions(delta.getBaseMappings(), delta.getDeletions(), path); 60 Collection<ClassEntry> changedClasses = delta.getChangedRoots()
60
61 Collection<ClassEntry> classes = delta.getAdditions().getRootEntries().stream()
62 .filter(entry -> entry instanceof ClassEntry) 61 .filter(entry -> entry instanceof ClassEntry)
63 .map(entry -> (ClassEntry) entry) 62 .map(entry -> (ClassEntry) entry)
64 .collect(Collectors.toList()); 63 .collect(Collectors.toList());
65 64
66 progress.init(classes.size(), "Writing classes"); 65 applyDeletions(path, changedClasses, mappings, delta.getBaseMappings());
66
67 progress.init(changedClasses.size(), "Writing classes");
67 68
68 Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE);
69 AtomicInteger steps = new AtomicInteger(); 69 AtomicInteger steps = new AtomicInteger();
70 70
71 classes.parallelStream().forEach(classEntry -> { 71 Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE);
72 changedClasses.parallelStream().forEach(classEntry -> {
72 progress.step(steps.getAndIncrement(), classEntry.getFullName()); 73 progress.step(steps.getAndIncrement(), classEntry.getFullName());
73 74
74 try { 75 try {
@@ -86,12 +87,12 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
86 }); 87 });
87 } 88 }
88 89
89 private void applyDeletions(EntryTree<EntryMapping> baseMappings, EntryTree<?> deletions, Path root) { 90 private void applyDeletions(Path root, Collection<ClassEntry> changedClasses, EntryTree<EntryMapping> mappings, EntryTree<EntryMapping> oldMappings) {
90 Translator oldMappingTranslator = new MappingTranslator(baseMappings, VoidEntryResolver.INSTANCE); 91 Translator oldMappingTranslator = new MappingTranslator(oldMappings, VoidEntryResolver.INSTANCE);
91 92
92 Collection<ClassEntry> deletedClasses = deletions.getRootEntries().stream() 93 Collection<ClassEntry> deletedClasses = changedClasses.stream()
93 .filter(e -> e instanceof ClassEntry) 94 .filter(e -> !Objects.equals(oldMappings.get(e), mappings.get(e)))
94 .map(e -> oldMappingTranslator.translate((ClassEntry) e)) 95 .map(oldMappingTranslator::translate)
95 .collect(Collectors.toList()); 96 .collect(Collectors.toList());
96 97
97 for (ClassEntry classEntry : deletedClasses) { 98 for (ClassEntry classEntry : deletedClasses) {
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java
index 622a0e15..25283523 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java
@@ -35,11 +35,11 @@ public enum MappingFormat {
35 writer.write(mappings, delta, path, progressListener); 35 writer.write(mappings, delta, path, progressListener);
36 } 36 }
37 37
38 public EntryTree<EntryMapping> read(Path path) throws IOException, MappingParseException { 38 public EntryTree<EntryMapping> read(Path path, ProgressListener progressListener) throws IOException, MappingParseException {
39 if (reader == null) { 39 if (reader == null) {
40 throw new IllegalStateException(name() + " does not support reading"); 40 throw new IllegalStateException(name() + " does not support reading");
41 } 41 }
42 return reader.read(path); 42 return reader.read(path, progressListener);
43 } 43 }
44 44
45 @Nullable 45 @Nullable
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java
index f239ee67..af0933f6 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java
@@ -1,5 +1,6 @@
1package cuchaz.enigma.translation.mapping.serde; 1package cuchaz.enigma.translation.mapping.serde;
2 2
3import cuchaz.enigma.ProgressListener;
3import cuchaz.enigma.throwables.MappingParseException; 4import cuchaz.enigma.throwables.MappingParseException;
4import cuchaz.enigma.translation.mapping.EntryMapping; 5import cuchaz.enigma.translation.mapping.EntryMapping;
5import cuchaz.enigma.translation.mapping.tree.EntryTree; 6import cuchaz.enigma.translation.mapping.tree.EntryTree;
@@ -8,5 +9,5 @@ import java.io.IOException;
8import java.nio.file.Path; 9import java.nio.file.Path;
9 10
10public interface MappingsReader { 11public interface MappingsReader {
11 EntryTree<EntryMapping> read(Path path) throws MappingParseException, IOException; 12 EntryTree<EntryMapping> read(Path path, ProgressListener progress) throws MappingParseException, IOException;
12} 13}
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java
index e0afc3e8..69d82354 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java
@@ -1,11 +1,12 @@
1package cuchaz.enigma.translation.mapping.serde; 1package cuchaz.enigma.translation.mapping.serde;
2 2
3import com.google.common.base.Charsets; 3import com.google.common.base.Charsets;
4import cuchaz.enigma.ProgressListener;
4import cuchaz.enigma.throwables.MappingParseException; 5import cuchaz.enigma.throwables.MappingParseException;
5import cuchaz.enigma.translation.mapping.EntryMapping; 6import cuchaz.enigma.translation.mapping.EntryMapping;
6import cuchaz.enigma.translation.mapping.MappingPair; 7import cuchaz.enigma.translation.mapping.MappingPair;
7import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
8import cuchaz.enigma.translation.mapping.tree.EntryTree; 8import cuchaz.enigma.translation.mapping.tree.EntryTree;
9import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
9import cuchaz.enigma.translation.representation.MethodDescriptor; 10import cuchaz.enigma.translation.representation.MethodDescriptor;
10import cuchaz.enigma.translation.representation.TypeDescriptor; 11import cuchaz.enigma.translation.representation.TypeDescriptor;
11import cuchaz.enigma.translation.representation.entry.ClassEntry; 12import cuchaz.enigma.translation.representation.entry.ClassEntry;
@@ -22,15 +23,19 @@ public enum TinyMappingsReader implements MappingsReader {
22 INSTANCE; 23 INSTANCE;
23 24
24 @Override 25 @Override
25 public EntryTree<EntryMapping> read(Path path) throws IOException, MappingParseException { 26 public EntryTree<EntryMapping> read(Path path, ProgressListener progress) throws IOException, MappingParseException {
26 return read(path, Files.readAllLines(path, Charsets.UTF_8)); 27 return read(path, Files.readAllLines(path, Charsets.UTF_8), progress);
27 } 28 }
28 29
29 private EntryTree<EntryMapping> read(Path path, List<String> lines) throws MappingParseException { 30 private EntryTree<EntryMapping> read(Path path, List<String> lines, ProgressListener progress) throws MappingParseException {
30 EntryTree<EntryMapping> mappings = new HashEntryTree<>(); 31 EntryTree<EntryMapping> mappings = new HashEntryTree<>();
31 lines.remove(0); 32 lines.remove(0);
32 33
34 progress.init(lines.size(), "Loading mapping file");
35
33 for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) { 36 for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) {
37 progress.step(lineNumber, "");
38
34 String line = lines.get(lineNumber); 39 String line = lines.get(lineNumber);
35 40
36 try { 41 try {
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java b/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java
index 36be5e1e..255fa5fb 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java
@@ -10,13 +10,13 @@ import cuchaz.enigma.translation.representation.entry.Entry;
10import javax.annotation.Nullable; 10import javax.annotation.Nullable;
11import java.util.Collection; 11import java.util.Collection;
12import java.util.Iterator; 12import java.util.Iterator;
13import java.util.stream.Stream;
13 14
14public class DeltaTrackingTree<T> implements EntryTree<T> { 15public class DeltaTrackingTree<T> implements EntryTree<T> {
15 private final EntryTree<T> delegate; 16 private final EntryTree<T> delegate;
16 17
17 private EntryTree<T> deltaReference; 18 private EntryTree<T> deltaReference;
18 private EntryTree<Object> additions = new HashEntryTree<>(); 19 private EntryTree<Object> changes = new HashEntryTree<>();
19 private EntryTree<Object> deletions = new HashEntryTree<>();
20 20
21 public DeltaTrackingTree(EntryTree<T> delegate) { 21 public DeltaTrackingTree(EntryTree<T> delegate) {
22 this.delegate = delegate; 22 this.delegate = delegate;
@@ -29,30 +29,19 @@ public class DeltaTrackingTree<T> implements EntryTree<T> {
29 29
30 @Override 30 @Override
31 public void insert(Entry<?> entry, T value) { 31 public void insert(Entry<?> entry, T value) {
32 if (value != null) { 32 trackChange(entry);
33 trackAddition(entry);
34 } else {
35 trackDeletion(entry);
36 }
37 delegate.insert(entry, value); 33 delegate.insert(entry, value);
38 } 34 }
39 35
40 @Nullable 36 @Nullable
41 @Override 37 @Override
42 public T remove(Entry<?> entry) { 38 public T remove(Entry<?> entry) {
43 T value = delegate.remove(entry); 39 trackChange(entry);
44 trackDeletion(entry); 40 return delegate.remove(entry);
45 return value;
46 } 41 }
47 42
48 public void trackAddition(Entry<?> entry) { 43 public void trackChange(Entry<?> entry) {
49 deletions.insert(entry, MappingDelta.PLACEHOLDER); 44 changes.insert(entry, MappingDelta.PLACEHOLDER);
50 additions.insert(entry, MappingDelta.PLACEHOLDER);
51 }
52
53 public void trackDeletion(Entry<?> entry) {
54 additions.remove(entry);
55 deletions.insert(entry, MappingDelta.PLACEHOLDER);
56 } 45 }
57 46
58 @Nullable 47 @Nullable
@@ -78,25 +67,19 @@ public class DeltaTrackingTree<T> implements EntryTree<T> {
78 } 67 }
79 68
80 @Override 69 @Override
81 public Collection<EntryTreeNode<T>> getAllNodes() { 70 public Stream<EntryTreeNode<T>> getRootNodes() {
82 return delegate.getAllNodes(); 71 return delegate.getRootNodes();
83 }
84
85 @Override
86 public Collection<Entry<?>> getRootEntries() {
87 return delegate.getRootEntries();
88 } 72 }
89 73
90 @Override 74 @Override
91 public DeltaTrackingTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { 75 public DeltaTrackingTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
92 DeltaTrackingTree<T> translatedTree = new DeltaTrackingTree<>(delegate.translate(translator, resolver, mappings)); 76 DeltaTrackingTree<T> translatedTree = new DeltaTrackingTree<>(delegate.translate(translator, resolver, mappings));
93 translatedTree.additions = additions.translate(translator, resolver, mappings); 77 translatedTree.changes = changes.translate(translator, resolver, mappings);
94 translatedTree.deletions = deletions.translate(translator, resolver, mappings);
95 return translatedTree; 78 return translatedTree;
96 } 79 }
97 80
98 @Override 81 @Override
99 public Collection<Entry<?>> getAllEntries() { 82 public Stream<Entry<?>> getAllEntries() {
100 return delegate.getAllEntries(); 83 return delegate.getAllEntries();
101 } 84 }
102 85
@@ -111,18 +94,17 @@ public class DeltaTrackingTree<T> implements EntryTree<T> {
111 } 94 }
112 95
113 public MappingDelta<T> takeDelta() { 96 public MappingDelta<T> takeDelta() {
114 MappingDelta<T> delta = new MappingDelta<>(deltaReference, additions, deletions); 97 MappingDelta<T> delta = new MappingDelta<>(deltaReference, changes);
115 resetDelta(); 98 resetDelta();
116 return delta; 99 return delta;
117 } 100 }
118 101
119 private void resetDelta() { 102 private void resetDelta() {
120 deltaReference = new HashEntryTree<>(delegate); 103 deltaReference = new HashEntryTree<>(delegate);
121 additions = new HashEntryTree<>(); 104 changes = new HashEntryTree<>();
122 deletions = new HashEntryTree<>();
123 } 105 }
124 106
125 public boolean isDirty() { 107 public boolean isDirty() {
126 return !additions.isEmpty() || !deletions.isEmpty(); 108 return !changes.isEmpty();
127 } 109 }
128} 110}
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTree.java b/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTree.java
index 4f341f45..daaefcc1 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTree.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTree.java
@@ -9,6 +9,7 @@ import cuchaz.enigma.translation.representation.entry.Entry;
9 9
10import javax.annotation.Nullable; 10import javax.annotation.Nullable;
11import java.util.Collection; 11import java.util.Collection;
12import java.util.stream.Stream;
12 13
13public interface EntryTree<T> extends EntryMap<T>, Iterable<EntryTreeNode<T>>, Translatable { 14public interface EntryTree<T> extends EntryMap<T>, Iterable<EntryTreeNode<T>>, Translatable {
14 Collection<Entry<?>> getChildren(Entry<?> entry); 15 Collection<Entry<?>> getChildren(Entry<?> entry);
@@ -18,9 +19,7 @@ public interface EntryTree<T> extends EntryMap<T>, Iterable<EntryTreeNode<T>>, T
18 @Nullable 19 @Nullable
19 EntryTreeNode<T> findNode(Entry<?> entry); 20 EntryTreeNode<T> findNode(Entry<?> entry);
20 21
21 Collection<EntryTreeNode<T>> getAllNodes(); 22 Stream<EntryTreeNode<T>> getRootNodes();
22
23 Collection<Entry<?>> getRootEntries();
24 23
25 @Override 24 @Override
26 EntryTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings); 25 EntryTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings);
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java b/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java
index 734b60ce..affcd504 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java
@@ -33,4 +33,8 @@ public interface EntryTreeNode<T> {
33 .map(EntryTreeNode::getEntry) 33 .map(EntryTreeNode::getEntry)
34 .collect(Collectors.toList()); 34 .collect(Collectors.toList());
35 } 35 }
36
37 default boolean hasValue() {
38 return getValue() != null;
39 }
36} 40}
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java b/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java
index c5fc473d..bb21de6f 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java
@@ -8,7 +8,9 @@ import cuchaz.enigma.translation.representation.entry.Entry;
8 8
9import javax.annotation.Nullable; 9import javax.annotation.Nullable;
10import java.util.*; 10import java.util.*;
11import java.util.stream.Collectors; 11import java.util.function.Function;
12import java.util.stream.Stream;
13import java.util.stream.StreamSupport;
12 14
13public class HashEntryTree<T> implements EntryTree<T> { 15public class HashEntryTree<T> implements EntryTree<T> {
14 private final Map<Entry<?>, HashTreeNode<T>> root = new HashMap<>(); 16 private final Map<Entry<?>, HashTreeNode<T>> root = new HashMap<>();
@@ -17,7 +19,7 @@ public class HashEntryTree<T> implements EntryTree<T> {
17 } 19 }
18 20
19 public HashEntryTree(EntryTree<T> tree) { 21 public HashEntryTree(EntryTree<T> tree) {
20 for (EntryTreeNode<T> node : tree.getAllNodes()) { 22 for (EntryTreeNode<T> node : tree) {
21 insert(node.getEntry(), node.getValue()); 23 insert(node.getEntry(), node.getValue());
22 } 24 }
23 } 25 }
@@ -151,31 +153,24 @@ public class HashEntryTree<T> implements EntryTree<T> {
151 } 153 }
152 154
153 @Override 155 @Override
154 @SuppressWarnings("unchecked")
155 public Iterator<EntryTreeNode<T>> iterator() { 156 public Iterator<EntryTreeNode<T>> iterator() {
156 Collection<EntryTreeNode<T>> values = (Collection) root.values();
157 return values.iterator();
158 }
159
160 @Override
161 public Collection<EntryTreeNode<T>> getAllNodes() {
162 Collection<EntryTreeNode<T>> nodes = new ArrayList<>(); 157 Collection<EntryTreeNode<T>> nodes = new ArrayList<>();
163 for (EntryTreeNode<T> node : root.values()) { 158 for (EntryTreeNode<T> node : root.values()) {
164 nodes.addAll(node.getNodesRecursively()); 159 nodes.addAll(node.getNodesRecursively());
165 } 160 }
166 return nodes; 161 return nodes.iterator();
167 } 162 }
168 163
169 @Override 164 @Override
170 public Collection<Entry<?>> getAllEntries() { 165 public Stream<Entry<?>> getAllEntries() {
171 return getAllNodes().stream() 166 return StreamSupport.stream(spliterator(), false)
172 .map(EntryTreeNode::getEntry) 167 .filter(EntryTreeNode::hasValue)
173 .collect(Collectors.toList()); 168 .map(EntryTreeNode::getEntry);
174 } 169 }
175 170
176 @Override 171 @Override
177 public Collection<Entry<?>> getRootEntries() { 172 public Stream<EntryTreeNode<T>> getRootNodes() {
178 return root.keySet(); 173 return root.values().stream().map(Function.identity());
179 } 174 }
180 175
181 @Override 176 @Override
@@ -186,7 +181,7 @@ public class HashEntryTree<T> implements EntryTree<T> {
186 @Override 181 @Override
187 public HashEntryTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { 182 public HashEntryTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
188 HashEntryTree<T> translatedTree = new HashEntryTree<>(); 183 HashEntryTree<T> translatedTree = new HashEntryTree<>();
189 for (EntryTreeNode<T> node : getAllNodes()) { 184 for (EntryTreeNode<T> node : this) {
190 translatedTree.insert(translator.translate(node.getEntry()), node.getValue()); 185 translatedTree.insert(translator.translate(node.getEntry()), node.getValue());
191 } 186 }
192 return translatedTree; 187 return translatedTree;
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java
index b9391b04..c4df891c 100644
--- a/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java
@@ -86,6 +86,11 @@ public class ClassDefEntry extends ClassEntry implements DefEntry<ClassEntry> {
86 } 86 }
87 87
88 @Override 88 @Override
89 public ClassDefEntry withName(String name) {
90 return new ClassDefEntry(parent, name, signature, access, superClass, interfaces);
91 }
92
93 @Override
89 public ClassDefEntry withParent(ClassEntry parent) { 94 public ClassDefEntry withParent(ClassEntry parent) {
90 return new ClassDefEntry(parent, name, signature, access, superClass, interfaces); 95 return new ClassDefEntry(parent, name, signature, access, superClass, interfaces);
91 } 96 }
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
index 644658fd..9bfcd8a8 100644
--- a/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
@@ -96,6 +96,11 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
96 } 96 }
97 97
98 @Override 98 @Override
99 public ClassEntry withName(String name) {
100 return new ClassEntry(parent, name);
101 }
102
103 @Override
99 public ClassEntry withParent(ClassEntry parent) { 104 public ClassEntry withParent(ClassEntry parent) {
100 return new ClassEntry(parent, name); 105 return new ClassEntry(parent, name);
101 } 106 }
@@ -193,6 +198,11 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
193 198
194 @Override 199 @Override
195 public int compareTo(ClassEntry entry) { 200 public int compareTo(ClassEntry entry) {
196 return name.compareTo(entry.name); 201 String fullName = getFullName();
202 String otherFullName = entry.getFullName();
203 if (fullName.length() != otherFullName.length()) {
204 return fullName.length() - otherFullName.length();
205 }
206 return fullName.compareTo(otherFullName);
197 } 207 }
198} 208}
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
index 227400eb..29a55d89 100644
--- a/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
@@ -31,6 +31,8 @@ public interface Entry<P extends Entry<?>> extends Translatable {
31 31
32 Class<P> getParentType(); 32 Class<P> getParentType();
33 33
34 Entry<P> withName(String name);
35
34 Entry<P> withParent(P parent); 36 Entry<P> withParent(P parent);
35 37
36 boolean canConflictWith(Entry<?> entry); 38 boolean canConflictWith(Entry<?> entry);
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java
index d487f71f..27033015 100644
--- a/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java
@@ -55,6 +55,11 @@ public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> {
55 } 55 }
56 56
57 @Override 57 @Override
58 public FieldDefEntry withName(String name) {
59 return new FieldDefEntry(parent, name, desc, signature, access);
60 }
61
62 @Override
58 public FieldDefEntry withParent(ClassEntry owner) { 63 public FieldDefEntry withParent(ClassEntry owner) {
59 return new FieldDefEntry(owner, this.name, this.desc, signature, access); 64 return new FieldDefEntry(owner, this.name, this.desc, signature, access);
60 } 65 }
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java
index 2ec24719..700512e2 100644
--- a/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java
@@ -45,6 +45,11 @@ public class FieldEntry extends ParentedEntry<ClassEntry> implements Comparable<
45 } 45 }
46 46
47 @Override 47 @Override
48 public FieldEntry withName(String name) {
49 return new FieldEntry(parent, name, desc);
50 }
51
52 @Override
48 public FieldEntry withParent(ClassEntry parent) { 53 public FieldEntry withParent(ClassEntry parent) {
49 return new FieldEntry(parent, this.name, this.desc); 54 return new FieldEntry(parent, this.name, this.desc);
50 } 55 }
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java
index 86bdf61c..c6f32b62 100644
--- a/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java
@@ -34,6 +34,11 @@ public class LocalVariableDefEntry extends LocalVariableEntry {
34 } 34 }
35 35
36 @Override 36 @Override
37 public LocalVariableDefEntry withName(String name) {
38 return new LocalVariableDefEntry(parent, index, name, parameter, desc);
39 }
40
41 @Override
37 public LocalVariableDefEntry withParent(MethodEntry entry) { 42 public LocalVariableDefEntry withParent(MethodEntry entry) {
38 return new LocalVariableDefEntry(entry, index, name, parameter, desc); 43 return new LocalVariableDefEntry(entry, index, name, parameter, desc);
39 } 44 }
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java
index 0c12f1c8..6fdb79fe 100644
--- a/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java
@@ -52,6 +52,11 @@ public class LocalVariableEntry extends ParentedEntry<MethodEntry> implements Co
52 } 52 }
53 53
54 @Override 54 @Override
55 public LocalVariableEntry withName(String name) {
56 return new LocalVariableEntry(parent, index, name, parameter);
57 }
58
59 @Override
55 public LocalVariableEntry withParent(MethodEntry parent) { 60 public LocalVariableEntry withParent(MethodEntry parent) {
56 return new LocalVariableEntry(parent, index, name, parameter); 61 return new LocalVariableEntry(parent, index, name, parameter);
57 } 62 }
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java
index 3ecd470f..51842443 100644
--- a/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java
@@ -55,6 +55,11 @@ public class MethodDefEntry extends MethodEntry implements DefEntry<ClassEntry>
55 } 55 }
56 56
57 @Override 57 @Override
58 public MethodDefEntry withName(String name) {
59 return new MethodDefEntry(parent, name, descriptor, signature, access);
60 }
61
62 @Override
58 public MethodDefEntry withParent(ClassEntry parent) { 63 public MethodDefEntry withParent(ClassEntry parent) {
59 return new MethodDefEntry(new ClassEntry(parent.getFullName()), name, descriptor, signature, access); 64 return new MethodDefEntry(new ClassEntry(parent.getFullName()), name, descriptor, signature, access);
60 } 65 }
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java
index 3a1dbb32..f5d5c744 100644
--- a/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java
@@ -56,6 +56,11 @@ public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable
56 } 56 }
57 57
58 @Override 58 @Override
59 public MethodEntry withName(String name) {
60 return new MethodEntry(parent, name, descriptor);
61 }
62
63 @Override
59 public MethodEntry withParent(ClassEntry parent) { 64 public MethodEntry withParent(ClassEntry parent) {
60 return new MethodEntry(new ClassEntry(parent.getFullName()), name, descriptor); 65 return new MethodEntry(new ClassEntry(parent.getFullName()), name, descriptor);
61 } 66 }
diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java
index 7ba7c196..834da8de 100644
--- a/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java
+++ b/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java
@@ -35,6 +35,9 @@ public abstract class ParentedEntry<P extends Entry<?>> implements Entry<P> {
35 @Override 35 @Override
36 public abstract ParentedEntry<P> withParent(P parent); 36 public abstract ParentedEntry<P> withParent(P parent);
37 37
38 @Override
39 public abstract ParentedEntry<P> withName(String name);
40
38 protected abstract ParentedEntry<P> translate(Translator translator, @Nullable EntryMapping mapping); 41 protected abstract ParentedEntry<P> translate(Translator translator, @Nullable EntryMapping mapping);
39 42
40 @Override 43 @Override