- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma;
@@ -35,12 +35,12 @@ import cuchaz.enigma.classprovider.JarClassProvider;
import cuchaz.enigma.utils.Utils;
public class Enigma {
- public static final String NAME = "Enigma";
+ public static final String NAME = "Enigma";
public static final String VERSION;
public static final String URL = "https://fabricmc.net";
- public static final int ASM_VERSION = Opcodes.ASM9;
+ public static final int ASM_VERSION = Opcodes.ASM9;
- private final EnigmaProfile profile;
+ private final EnigmaProfile profile;
private final EnigmaServices services;
private Enigma(EnigmaProfile profile, EnigmaServices services) {
@@ -97,6 +97,7 @@ public class Enigma {
public Enigma build() {
PluginContext pluginContext = new PluginContext(profile);
+
for (EnigmaPlugin plugin : plugins) {
plugin.init(pluginContext);
}
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java
index daf2727..f95bf1e 100644
--- a/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java
+++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java
@@ -1,5 +1,20 @@
package cuchaz.enigma;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.annotation.Nullable;
+
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -10,31 +25,16 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
+
import cuchaz.enigma.api.service.EnigmaServiceType;
import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat;
import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
-import javax.annotation.Nullable;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.lang.reflect.Type;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
public final class EnigmaProfile {
public static final EnigmaProfile EMPTY = new EnigmaProfile(new ServiceContainer(ImmutableMap.of()));
private static final MappingSaveParameters DEFAULT_MAPPING_SAVE_PARAMETERS = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF);
- private static final Gson GSON = new GsonBuilder()
- .registerTypeAdapter(ServiceContainer.class, (JsonDeserializer) EnigmaProfile::loadServiceContainer)
- .create();
+ private static final Gson GSON = new GsonBuilder().registerTypeAdapter(ServiceContainer.class, (JsonDeserializer) EnigmaProfile::loadServiceContainer).create();
private static final Type SERVICE_LIST_TYPE = new TypeToken>() {
}.getType();
@@ -78,6 +78,7 @@ public final class EnigmaProfile {
for (Map.Entry entry : object.entrySet()) {
JsonElement value = entry.getValue();
+
if (value.isJsonObject()) {
builder.put(entry.getKey(), Collections.singletonList(GSON.fromJson(value, Service.class)));
} else if (value.isJsonArray()) {
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java
index 4f50f2f..15d5e98 100644
--- a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java
+++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java
@@ -18,16 +18,16 @@ import java.util.stream.Stream;
import com.google.common.base.Functions;
import com.google.common.base.Preconditions;
-import cuchaz.enigma.api.service.ObfuscationTestService;
-import cuchaz.enigma.classprovider.ObfuscationFixClassProvider;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import cuchaz.enigma.analysis.EntryReference;
import cuchaz.enigma.analysis.index.JarIndex;
import cuchaz.enigma.api.service.NameProposalService;
+import cuchaz.enigma.api.service.ObfuscationTestService;
import cuchaz.enigma.bytecode.translators.TranslationClassVisitor;
import cuchaz.enigma.classprovider.ClassProvider;
+import cuchaz.enigma.classprovider.ObfuscationFixClassProvider;
import cuchaz.enigma.source.Decompiler;
import cuchaz.enigma.source.DecompilerService;
import cuchaz.enigma.source.SourceSettings;
@@ -101,6 +101,7 @@ public class EnigmaProject {
DeltaTrackingTree mappings = mapper.getObfToDeobf();
Collection> dropped = dropMappings(mappings, progress);
+
for (Entry> entry : dropped) {
mappings.trackChange(entry);
}
@@ -112,6 +113,7 @@ public class EnigmaProject {
MappingsChecker.Dropped dropped = checker.dropBrokenMappings(progress);
Map, String> droppedMappings = dropped.getDroppedMappings();
+
for (Map.Entry, String> mapping : droppedMappings.entrySet()) {
System.out.println("WARNING: Couldn't find " + mapping.getKey() + " (" + mapping.getValue() + ") in jar. Mapping was dropped.");
}
@@ -124,6 +126,7 @@ public class EnigmaProject {
// HACKHACK: Object methods are not obfuscated identifiers
String name = obfMethodEntry.getName();
String sig = obfMethodEntry.getDesc().toString();
+
//TODO replace with a map or check if declaring class is java.lang.Object
if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) {
return false;
@@ -163,6 +166,7 @@ public class EnigmaProject {
String name = entry.getName();
List obfuscationTestServices = this.getEnigma().getServices().get(ObfuscationTestService.TYPE);
+
if (!obfuscationTestServices.isEmpty()) {
for (ObfuscationTestService service : obfuscationTestServices) {
if (service.testDeobfuscated(entry)) {
@@ -172,6 +176,7 @@ public class EnigmaProject {
}
List nameProposalServices = this.getEnigma().getServices().get(NameProposalService.TYPE);
+
if (!nameProposalServices.isEmpty()) {
for (NameProposalService service : nameProposalServices) {
if (service.proposeName(entry, mapper).isPresent()) {
@@ -181,6 +186,7 @@ public class EnigmaProject {
}
String mappedName = mapper.deobfuscate(entry).getName();
+
if (mappedName != null && !mappedName.isEmpty() && !mappedName.equals(name)) {
return false;
}
@@ -198,22 +204,20 @@ public class EnigmaProject {
AtomicInteger count = new AtomicInteger();
progress.init(classEntries.size(), I18n.translate("progress.classes.deobfuscating"));
- Map compiled = classEntries.parallelStream()
- .map(entry -> {
- ClassEntry translatedEntry = deobfuscator.translate(entry);
- progress.step(count.getAndIncrement(), translatedEntry.toString());
+ Map compiled = classEntries.parallelStream().map(entry -> {
+ ClassEntry translatedEntry = deobfuscator.translate(entry);
+ progress.step(count.getAndIncrement(), translatedEntry.toString());
- ClassNode node = fixingClassProvider.get(entry.getFullName());
- if (node != null) {
- ClassNode translatedNode = new ClassNode();
- node.accept(new TranslationClassVisitor(deobfuscator, Enigma.ASM_VERSION, translatedNode));
- return translatedNode;
- }
+ ClassNode node = fixingClassProvider.get(entry.getFullName());
- return null;
- })
- .filter(Objects::nonNull)
- .collect(Collectors.toMap(n -> n.name, Functions.identity()));
+ if (node != null) {
+ ClassNode translatedNode = new ClassNode();
+ node.accept(new TranslationClassVisitor(deobfuscator, Enigma.ASM_VERSION, translatedNode));
+ return translatedNode;
+ }
+
+ return null;
+ }).filter(Objects::nonNull).collect(Collectors.toMap(n -> n.name, Functions.identity()));
return new JarExport(mapper, compiled);
}
@@ -254,9 +258,7 @@ public class EnigmaProject {
}
public Stream decompileStream(ProgressListener progress, DecompilerService decompilerService, DecompileErrorStrategy errorStrategy) {
- Collection classes = this.compiled.values().stream()
- .filter(classNode -> classNode.name.indexOf('$') == -1)
- .toList();
+ Collection classes = this.compiled.values().stream().filter(classNode -> classNode.name.indexOf('$') == -1).toList();
progress.init(classes.size(), I18n.translate("progress.classes.decompiling"));
@@ -265,33 +267,34 @@ public class EnigmaProject {
AtomicInteger count = new AtomicInteger();
- return classes.parallelStream()
- .map(translatedNode -> {
- progress.step(count.getAndIncrement(), translatedNode.name);
-
- String source = null;
- try {
- source = decompileClass(translatedNode, decompiler);
- } catch (Throwable throwable) {
- switch (errorStrategy) {
- case PROPAGATE: throw throwable;
- case IGNORE: break;
- case TRACE_AS_SOURCE: {
- StringWriter writer = new StringWriter();
- throwable.printStackTrace(new PrintWriter(writer));
- source = writer.toString();
- break;
- }
- }
- }
-
- if (source == null) {
- return null;
- }
-
- return new ClassSource(translatedNode.name, source);
- })
- .filter(Objects::nonNull);
+ return classes.parallelStream().map(translatedNode -> {
+ progress.step(count.getAndIncrement(), translatedNode.name);
+
+ String source = null;
+
+ try {
+ source = decompileClass(translatedNode, decompiler);
+ } catch (Throwable throwable) {
+ switch (errorStrategy) {
+ case PROPAGATE:
+ throw throwable;
+ case IGNORE:
+ break;
+ case TRACE_AS_SOURCE: {
+ StringWriter writer = new StringWriter();
+ throwable.printStackTrace(new PrintWriter(writer));
+ source = writer.toString();
+ break;
+ }
+ }
+ }
+
+ if (source == null) {
+ return null;
+ }
+
+ return new ClassSource(translatedNode.name, source);
+ }).filter(Objects::nonNull);
}
private String decompileClass(ClassNode translatedNode, Decompiler decompiler) {
@@ -310,6 +313,7 @@ public class EnigmaProject {
progress.init(decompiled.size(), I18n.translate("progress.sources.writing"));
int count = 0;
+
for (ClassSource source : decompiled) {
progress.step(count++, source.name);
@@ -329,7 +333,6 @@ public class EnigmaProject {
}
public void writeTo(Path path) throws IOException {
- Files.createDirectories(path.getParent());
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
writer.write(source);
}
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java b/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java
index df3b7bb..bbdc684 100644
--- a/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java
+++ b/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java
@@ -1,11 +1,12 @@
package cuchaz.enigma;
+import java.util.List;
+
import com.google.common.collect.ImmutableListMultimap;
+
import cuchaz.enigma.api.service.EnigmaService;
import cuchaz.enigma.api.service.EnigmaServiceType;
-import java.util.List;
-
public final class EnigmaServices {
private final ImmutableListMultimap, EnigmaService> services;
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/Access.java b/enigma/src/main/java/cuchaz/enigma/analysis/Access.java
index 82ca669..cc7d121 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/Access.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/Access.java
@@ -1,23 +1,25 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis;
-import cuchaz.enigma.translation.representation.AccessFlags;
-
import java.lang.reflect.Modifier;
-public enum Access {
+import cuchaz.enigma.translation.representation.AccessFlags;
- PUBLIC, PROTECTED, PACKAGE, PRIVATE;
+public enum Access {
+ PUBLIC,
+ PROTECTED,
+ PACKAGE,
+ PRIVATE;
public static Access get(AccessFlags flags) {
return get(flags.getFlags());
@@ -37,6 +39,7 @@ public enum Access {
} else if (!isPublic && !isProtected && !isPrivate) {
return PACKAGE;
}
+
// assume public by default
return PUBLIC;
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java b/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java
index 013c52f..45dac2c 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java
@@ -1,17 +1,13 @@
package cuchaz.enigma.analysis;
-import cuchaz.enigma.Enigma;
-import cuchaz.enigma.api.EnigmaPlugin;
-import cuchaz.enigma.api.EnigmaPluginContext;
-import cuchaz.enigma.api.service.JarIndexerService;
-import cuchaz.enigma.api.service.NameProposalService;
-import cuchaz.enigma.source.DecompilerService;
-import cuchaz.enigma.source.Decompilers;
-import cuchaz.enigma.translation.representation.TypeDescriptor;
-import cuchaz.enigma.translation.representation.entry.ClassEntry;
-import cuchaz.enigma.translation.representation.entry.Entry;
-import cuchaz.enigma.translation.representation.entry.FieldEntry;
-import cuchaz.enigma.utils.Pair;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
@@ -27,16 +23,20 @@ import org.objectweb.asm.tree.analysis.Frame;
import org.objectweb.asm.tree.analysis.SourceInterpreter;
import org.objectweb.asm.tree.analysis.SourceValue;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
+import cuchaz.enigma.Enigma;
+import cuchaz.enigma.api.EnigmaPlugin;
+import cuchaz.enigma.api.EnigmaPluginContext;
+import cuchaz.enigma.api.service.JarIndexerService;
+import cuchaz.enigma.api.service.NameProposalService;
+import cuchaz.enigma.source.DecompilerService;
+import cuchaz.enigma.source.Decompilers;
+import cuchaz.enigma.translation.representation.TypeDescriptor;
+import cuchaz.enigma.translation.representation.entry.ClassEntry;
+import cuchaz.enigma.translation.representation.entry.Entry;
+import cuchaz.enigma.translation.representation.entry.FieldEntry;
+import cuchaz.enigma.utils.Pair;
public final class BuiltinPlugin implements EnigmaPlugin {
-
public BuiltinPlugin() {
}
@@ -61,7 +61,6 @@ public final class BuiltinPlugin implements EnigmaPlugin {
}
private static final class EnumFieldNameFindingVisitor extends ClassVisitor {
-
private ClassEntry clazz;
private String className;
private final Map, String> mappings;
@@ -89,6 +88,7 @@ public final class BuiltinPlugin implements EnigmaPlugin {
throw new IllegalArgumentException("Found two enum fields with the same name \"" + name + "\" and desc \"" + descriptor + "\"!");
}
}
+
return super.visitField(access, name, descriptor, signature, value);
}
@@ -99,12 +99,14 @@ public final class BuiltinPlugin implements EnigmaPlugin {
classInits.add(node);
return node;
}
+
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
@Override
public void visitEnd() {
super.visitEnd();
+
try {
collectResults();
} catch (Exception ex) {
@@ -118,21 +120,18 @@ public final class BuiltinPlugin implements EnigmaPlugin {
for (MethodNode mn : classInits) {
Frame[] frames = analyzer.analyze(className, mn);
-
InsnList instrs = mn.instructions;
+
for (int i = 1; i < instrs.size(); i++) {
AbstractInsnNode instr1 = instrs.get(i - 1);
AbstractInsnNode instr2 = instrs.get(i);
String s = null;
- if (instr2.getOpcode() == Opcodes.PUTSTATIC
- && ((FieldInsnNode) instr2).owner.equals(owner)
- && enumFields.contains(new Pair<>(((FieldInsnNode) instr2).name, ((FieldInsnNode) instr2).desc))
- && instr1.getOpcode() == Opcodes.INVOKESPECIAL
- && "".equals(((MethodInsnNode) instr1).name)) {
-
+ if (instr2.getOpcode() == Opcodes.PUTSTATIC && ((FieldInsnNode) instr2).owner.equals(owner) && enumFields.contains(new Pair<>(((FieldInsnNode) instr2).name, ((FieldInsnNode) instr2).desc)) && instr1.getOpcode() == Opcodes.INVOKESPECIAL && "".equals(
+ ((MethodInsnNode) instr1).name)) {
for (int j = 0; j < frames[i - 1].getStackSize(); j++) {
SourceValue sv = frames[i - 1].getStack(j);
+
for (AbstractInsnNode ci : sv.insns) {
if (ci instanceof LdcInsnNode && ((LdcInsnNode) ci).cst instanceof String) {
//if (s == null || !s.equals(((LdcInsnNode) ci).cst)) {
@@ -148,6 +147,7 @@ public final class BuiltinPlugin implements EnigmaPlugin {
if (s != null) {
mappings.put(new FieldEntry(clazz, ((FieldInsnNode) instr2).name, new TypeDescriptor(((FieldInsnNode) instr2).desc)), s);
}
+
// report otherwise?
}
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
index 0fc44ca..8ef28d9 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
@@ -1,27 +1,29 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis;
+import java.util.Collection;
+import java.util.List;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
import com.google.common.collect.Lists;
+
import cuchaz.enigma.analysis.index.InheritanceIndex;
import cuchaz.enigma.analysis.index.JarIndex;
import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
-import javax.swing.tree.DefaultMutableTreeNode;
-import java.util.Collection;
-import java.util.List;
-
public class ClassImplementationsTreeNode extends DefaultMutableTreeNode {
private final Translator translator;
private final ClassEntry entry;
@@ -40,10 +42,12 @@ public class ClassImplementationsTreeNode extends DefaultMutableTreeNode {
// recurse
for (int i = 0; i < node.getChildCount(); i++) {
ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode) node.getChildAt(i), entry);
+
if (foundNode != null) {
return foundNode;
}
}
+
return null;
}
@@ -62,6 +66,7 @@ public class ClassImplementationsTreeNode extends DefaultMutableTreeNode {
InheritanceIndex inheritanceIndex = index.getInheritanceIndex();
Collection inheritors = inheritanceIndex.getChildren(entry);
+
for (ClassEntry inheritor : inheritors) {
nodes.add(new ClassImplementationsTreeNode(translator, inheritor));
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
index 788c534..24da23c 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
@@ -1,24 +1,26 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis;
+import java.util.List;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
import com.google.common.collect.Lists;
+
import cuchaz.enigma.analysis.index.InheritanceIndex;
import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
-import javax.swing.tree.DefaultMutableTreeNode;
-import java.util.List;
-
public class ClassInheritanceTreeNode extends DefaultMutableTreeNode {
private final Translator translator;
private final ClassEntry obfClassEntry;
@@ -37,10 +39,12 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode {
// recurse
for (int i = 0; i < node.getChildCount(); i++) {
ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode) node.getChildAt(i), entry);
+
if (foundNode != null) {
return foundNode;
}
}
+
return null;
}
@@ -63,6 +67,7 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode {
public void load(InheritanceIndex ancestries, boolean recurse) {
// get all the child nodes
List nodes = Lists.newArrayList();
+
for (ClassEntry inheritor : ancestries.getChildren(this.obfClassEntry)) {
nodes.add(new ClassInheritanceTreeNode(translator, inheritor.getFullName()));
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java
index 0142412..c76dca7 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java
@@ -1,17 +1,23 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis;
+import java.util.Set;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeNode;
+
import com.google.common.collect.Sets;
+
import cuchaz.enigma.analysis.index.JarIndex;
import cuchaz.enigma.analysis.index.ReferenceIndex;
import cuchaz.enigma.translation.Translator;
@@ -19,13 +25,7 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.translation.representation.entry.Entry;
import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.TreeNode;
-import java.util.Set;
-
-public class ClassReferenceTreeNode extends DefaultMutableTreeNode
- implements ReferenceTreeNode {
-
+public class ClassReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode {
private Translator deobfuscatingTranslator;
private ClassEntry entry;
private EntryReference reference;
@@ -57,6 +57,7 @@ public class ClassReferenceTreeNode extends DefaultMutableTreeNode
if (this.reference != null) {
return String.format("%s", this.deobfuscatingTranslator.translate(this.reference.context));
}
+
return this.deobfuscatingTranslator.translate(this.entry).getFullName();
}
@@ -71,16 +72,18 @@ public class ClassReferenceTreeNode extends DefaultMutableTreeNode
if (recurse && this.children != null) {
for (Object child : this.children) {
if (child instanceof ClassReferenceTreeNode node) {
-
// don't recurse into ancestor
Set> ancestors = Sets.newHashSet();
TreeNode n = node;
+
while (n.getParent() != null) {
n = n.getParent();
+
if (n instanceof ClassReferenceTreeNode) {
ancestors.add(((ClassReferenceTreeNode) n).getEntry());
}
}
+
if (ancestors.contains(node.getEntry())) {
continue;
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java b/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java
index 281b05f..9c54281 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java
@@ -1,13 +1,13 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis;
@@ -26,7 +26,6 @@ import cuchaz.enigma.translation.representation.entry.Entry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
public class EntryReference, C extends Entry>> implements Translatable {
-
private static final List CONSTRUCTOR_NON_NAMES = Arrays.asList("this", "super", "static");
public final E entry;
public final C context;
@@ -60,8 +59,7 @@ public class EntryReference, C extends Entry>> implements T
this.targetType = targetType;
this.declaration = declaration;
- this.sourceName = sourceName != null && !sourceName.isEmpty() &&
- !(entry instanceof MethodEntry && ((MethodEntry) entry).isConstructor() && CONSTRUCTOR_NON_NAMES.contains(sourceName));
+ this.sourceName = sourceName != null && !sourceName.isEmpty() && !(entry instanceof MethodEntry && ((MethodEntry) entry).isConstructor() && CONSTRUCTOR_NON_NAMES.contains(sourceName));
}
public EntryReference(E entry, C context, EntryReference other) {
@@ -76,6 +74,7 @@ public class EntryReference, C extends Entry>> implements T
if (context != null) {
return context.getContainingClass();
}
+
return entry.getContainingClass();
}
@@ -95,6 +94,7 @@ public class EntryReference, C extends Entry>> implements T
// renaming a constructor really means renaming the class
return entry.getContainingClass();
}
+
return entry;
}
@@ -107,6 +107,7 @@ public class EntryReference, C extends Entry>> implements T
if (context != null) {
return Objects.hash(entry.hashCode(), context.hashCode());
}
+
return entry.hashCode() ^ Boolean.hashCode(this.declaration);
}
@@ -116,10 +117,7 @@ public class EntryReference, C extends Entry>> implements T
}
public boolean equals(EntryReference, ?> other) {
- return other != null
- && Objects.equals(entry, other.entry)
- && Objects.equals(context, other.context)
- && declaration == other.declaration;
+ return other != null && Objects.equals(entry, other.entry) && Objects.equals(context, other.context) && declaration == other.declaration;
}
@Override
@@ -149,5 +147,4 @@ public class EntryReference, C extends Entry>> implements T
public TranslateResult> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap mappings) {
return translator.extendedTranslate(this.entry).map(e -> new EntryReference<>(e, translator.translate(context), this));
}
-
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
index c93ac53..cc511f3 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
@@ -1,16 +1,18 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis;
+import javax.swing.tree.DefaultMutableTreeNode;
+
import cuchaz.enigma.analysis.index.JarIndex;
import cuchaz.enigma.analysis.index.ReferenceIndex;
import cuchaz.enigma.translation.Translator;
@@ -18,10 +20,7 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry;
import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
-import javax.swing.tree.DefaultMutableTreeNode;
-
public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode {
-
private final Translator translator;
private FieldEntry entry;
private EntryReference reference;
@@ -53,6 +52,7 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re
if (this.reference != null) {
return String.format("%s", translator.translate(this.reference.context));
}
+
return translator.translate(entry).toString();
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java b/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java
index ec8f323..44a768e 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java
@@ -1,154 +1,160 @@
package cuchaz.enigma.analysis;
+import java.util.Set;
+
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.analysis.BasicValue;
+import org.objectweb.asm.tree.analysis.SimpleVerifier;
+
import cuchaz.enigma.Enigma;
import cuchaz.enigma.analysis.index.EntryIndex;
import cuchaz.enigma.analysis.index.InheritanceIndex;
import cuchaz.enigma.translation.representation.AccessFlags;
import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.analysis.BasicValue;
-import org.objectweb.asm.tree.analysis.SimpleVerifier;
-
-import java.util.Set;
public class IndexSimpleVerifier extends SimpleVerifier {
- private static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
- private final EntryIndex entryIndex;
- private final InheritanceIndex inheritanceIndex;
-
- public IndexSimpleVerifier(EntryIndex entryIndex, InheritanceIndex inheritanceIndex) {
- super(Enigma.ASM_VERSION, null, null, null, false);
- this.entryIndex = entryIndex;
- this.inheritanceIndex = inheritanceIndex;
- }
-
- @Override
- protected boolean isSubTypeOf(BasicValue value, BasicValue expected) {
- Type expectedType = expected.getType();
- Type type = value.getType();
- switch (expectedType.getSort()) {
- case Type.INT:
- case Type.FLOAT:
- case Type.LONG:
- case Type.DOUBLE:
- return type.equals(expectedType);
- case Type.ARRAY:
- case Type.OBJECT:
- if (type.equals(NULL_TYPE)) {
- return true;
- } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
- if (isAssignableFrom(expectedType, type)) {
- return true;
- } else if (isInterface(expectedType)) {
- return isAssignableFrom(OBJECT_TYPE, type);
- } else {
- return false;
- }
- } else {
- return false;
- }
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- protected boolean isInterface(Type type) {
- AccessFlags classAccess = entryIndex.getClassAccess(new ClassEntry(type.getInternalName()));
- if (classAccess != null) {
- return classAccess.isInterface();
- }
-
- Class> clazz = getClass(type);
- if (clazz != null) {
- return clazz.isInterface();
- }
-
- return false;
- }
-
- @Override
- protected Type getSuperClass(Type type) {
- ClassDefEntry definition = entryIndex.getDefinition(new ClassEntry(type.getInternalName()));
- if (definition != null) {
- return Type.getType('L' + definition.getSuperClass().getFullName() + ';');
- }
-
- Class> clazz = getClass(type);
- if (clazz != null) {
- return Type.getType(clazz.getSuperclass());
- }
-
- return OBJECT_TYPE;
- }
-
- @Override
- protected boolean isAssignableFrom(Type type1, Type type2) {
- if (type1.equals(type2)) {
- return true;
- }
-
- if (type2.equals(NULL_TYPE)) {
- return true;
- }
-
- if (type1.getSort() == Type.ARRAY) {
- return type2.getSort() == Type.ARRAY && isAssignableFrom(Type.getType(type1.getDescriptor().substring(1)), Type.getType(type2.getDescriptor().substring(1)));
- }
-
- if (type2.getSort() == Type.ARRAY) {
- return type1.equals(OBJECT_TYPE);
- }
-
- if (type1.getSort() == Type.OBJECT && type2.getSort() == Type.OBJECT) {
- if (type1.equals(OBJECT_TYPE)) {
- return true;
- }
-
- ClassEntry class1 = new ClassEntry(type1.getInternalName());
- ClassEntry class2 = new ClassEntry(type2.getInternalName());
-
- if (entryIndex.hasClass(class1) && entryIndex.hasClass(class2)) {
- return inheritanceIndex.getAncestors(class2).contains(class1);
- }
-
- Class> class1Class = getClass(Type.getType('L' + class1.getFullName() + ';'));
- Class> class2Class = getClass(Type.getType('L' + class2.getFullName() + ';'));
-
- if (class1Class == null) {
- return true; // missing classes to find out
- }
-
- if (class2Class != null) {
- return class1Class.isAssignableFrom(class2Class);
- }
-
- if (entryIndex.hasClass(class2)) {
- Set ancestors = inheritanceIndex.getAncestors(class2);
-
- for (ClassEntry ancestorEntry : ancestors) {
- Class> ancestor = getClass(Type.getType('L' + ancestorEntry.getFullName() + ';'));
- if (ancestor == null || class1Class.isAssignableFrom(ancestor)) {
- return true; // assignable, or missing classes to find out
- }
- }
-
- return false;
- }
-
- return true; // missing classes to find out
- }
-
- return false;
- }
-
- @Override
- protected final Class> getClass(Type type) {
- try {
- return Class.forName(type.getSort() == Type.ARRAY ? type.getDescriptor().replace('/', '.') : type.getClassName(), false, null);
- } catch (ClassNotFoundException e) {
- return null;
- }
- }
+ private static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
+ private final EntryIndex entryIndex;
+ private final InheritanceIndex inheritanceIndex;
+
+ public IndexSimpleVerifier(EntryIndex entryIndex, InheritanceIndex inheritanceIndex) {
+ super(Enigma.ASM_VERSION, null, null, null, false);
+ this.entryIndex = entryIndex;
+ this.inheritanceIndex = inheritanceIndex;
+ }
+
+ @Override
+ protected boolean isSubTypeOf(BasicValue value, BasicValue expected) {
+ Type expectedType = expected.getType();
+ Type type = value.getType();
+ switch (expectedType.getSort()) {
+ case Type.INT:
+ case Type.FLOAT:
+ case Type.LONG:
+ case Type.DOUBLE:
+ return type.equals(expectedType);
+ case Type.ARRAY:
+ case Type.OBJECT:
+ if (type.equals(NULL_TYPE)) {
+ return true;
+ } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
+ if (isAssignableFrom(expectedType, type)) {
+ return true;
+ } else if (isInterface(expectedType)) {
+ return isAssignableFrom(OBJECT_TYPE, type);
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ @Override
+ protected boolean isInterface(Type type) {
+ AccessFlags classAccess = entryIndex.getClassAccess(new ClassEntry(type.getInternalName()));
+
+ if (classAccess != null) {
+ return classAccess.isInterface();
+ }
+
+ Class> clazz = getClass(type);
+
+ if (clazz != null) {
+ return clazz.isInterface();
+ }
+
+ return false;
+ }
+
+ @Override
+ protected Type getSuperClass(Type type) {
+ ClassDefEntry definition = entryIndex.getDefinition(new ClassEntry(type.getInternalName()));
+
+ if (definition != null) {
+ return Type.getType('L' + definition.getSuperClass().getFullName() + ';');
+ }
+
+ Class> clazz = getClass(type);
+
+ if (clazz != null) {
+ return Type.getType(clazz.getSuperclass());
+ }
+
+ return OBJECT_TYPE;
+ }
+
+ @Override
+ protected boolean isAssignableFrom(Type type1, Type type2) {
+ if (type1.equals(type2)) {
+ return true;
+ }
+
+ if (type2.equals(NULL_TYPE)) {
+ return true;
+ }
+
+ if (type1.getSort() == Type.ARRAY) {
+ return type2.getSort() == Type.ARRAY && isAssignableFrom(Type.getType(type1.getDescriptor().substring(1)), Type.getType(type2.getDescriptor().substring(1)));
+ }
+
+ if (type2.getSort() == Type.ARRAY) {
+ return type1.equals(OBJECT_TYPE);
+ }
+
+ if (type1.getSort() == Type.OBJECT && type2.getSort() == Type.OBJECT) {
+ if (type1.equals(OBJECT_TYPE)) {
+ return true;
+ }
+
+ ClassEntry class1 = new ClassEntry(type1.getInternalName());
+ ClassEntry class2 = new ClassEntry(type2.getInternalName());
+
+ if (entryIndex.hasClass(class1) && entryIndex.hasClass(class2)) {
+ return inheritanceIndex.getAncestors(class2).contains(class1);
+ }
+
+ Class> class1Class = getClass(Type.getType('L' + class1.getFullName() + ';'));
+ Class> class2Class = getClass(Type.getType('L' + class2.getFullName() + ';'));
+
+ if (class1Class == null) {
+ return true; // missing classes to find out
+ }
+
+ if (class2Class != null) {
+ return class1Class.isAssignableFrom(class2Class);
+ }
+
+ if (entryIndex.hasClass(class2)) {
+ Set ancestors = inheritanceIndex.getAncestors(class2);
+
+ for (ClassEntry ancestorEntry : ancestors) {
+ Class> ancestor = getClass(Type.getType('L' + ancestorEntry.getFullName() + ';'));
+
+ if (ancestor == null || class1Class.isAssignableFrom(ancestor)) {
+ return true; // assignable, or missing classes to find out
+ }
+ }
+
+ return false;
+ }
+
+ return true; // missing classes to find out
+ }
+
+ return false;
+ }
+
+ @Override
+ protected final Class> getClass(Type type) {
+ try {
+ return Class.forName(type.getSort() == Type.ARRAY ? type.getDescriptor().replace('/', '.') : type.getClassName(), false, null);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java b/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java
index 0c2dfd7..3043577 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java
@@ -1,6 +1,10 @@
package cuchaz.enigma.analysis;
+import java.util.Collection;
+import java.util.List;
+
import com.google.common.collect.Lists;
+
import cuchaz.enigma.analysis.index.JarIndex;
import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.mapping.EntryResolver;
@@ -8,9 +12,6 @@ import cuchaz.enigma.translation.mapping.ResolutionStrategy;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
-import java.util.Collection;
-import java.util.List;
-
public class IndexTreeBuilder {
private final JarIndex index;
@@ -22,6 +23,7 @@ public class IndexTreeBuilder {
// get the root node
List ancestry = Lists.newArrayList();
ancestry.add(obfClassEntry.getFullName());
+
for (ClassEntry classEntry : index.getInheritanceIndex().getAncestors(obfClassEntry)) {
ancestry.add(classEntry.getFullName());
}
@@ -40,6 +42,7 @@ public class IndexTreeBuilder {
node.load(index);
return node;
}
+
return null;
}
@@ -47,10 +50,7 @@ public class IndexTreeBuilder {
MethodEntry resolvedEntry = index.getEntryResolver().resolveFirstEntry(obfMethodEntry, ResolutionStrategy.RESOLVE_ROOT);
// make a root node at the base
- MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode(
- translator, resolvedEntry,
- index.getEntryIndex().hasMethod(resolvedEntry)
- );
+ MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode(translator, resolvedEntry, index.getEntryIndex().hasMethod(resolvedEntry));
// expand the full tree
rootNode.load(index);
@@ -63,6 +63,7 @@ public class IndexTreeBuilder {
Collection resolvedEntries = resolver.resolveEntry(obfMethodEntry, ResolutionStrategy.RESOLVE_ROOT);
List nodes = Lists.newArrayList();
+
for (MethodEntry resolvedEntry : resolvedEntries) {
MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(translator, resolvedEntry);
node.load(index);
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java b/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java
index a624b7c..2ca1dfd 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java
@@ -1,129 +1,106 @@
package cuchaz.enigma.analysis;
-import cuchaz.enigma.Enigma;
+import java.util.List;
+import java.util.Objects;
+
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.Interpreter;
import org.objectweb.asm.tree.analysis.Value;
-import java.util.List;
-import java.util.Objects;
+import cuchaz.enigma.Enigma;
public class InterpreterPair extends Interpreter> {
- private final Interpreter left;
- private final Interpreter right;
-
- public InterpreterPair(Interpreter left, Interpreter right) {
- super(Enigma.ASM_VERSION);
- this.left = left;
- this.right = right;
- }
-
- @Override
- public PairValue newValue(Type type) {
- return pair(
- left.newValue(type),
- right.newValue(type)
- );
- }
-
- @Override
- public PairValue newOperation(AbstractInsnNode insn) throws AnalyzerException {
- return pair(
- left.newOperation(insn),
- right.newOperation(insn)
- );
- }
-
- @Override
- public PairValue copyOperation(AbstractInsnNode insn, PairValue value) throws AnalyzerException {
- return pair(
- left.copyOperation(insn, value.left),
- right.copyOperation(insn, value.right)
- );
- }
-
- @Override
- public PairValue unaryOperation(AbstractInsnNode insn, PairValue value) throws AnalyzerException {
- return pair(
- left.unaryOperation(insn, value.left),
- right.unaryOperation(insn, value.right)
- );
- }
-
- @Override
- public PairValue binaryOperation(AbstractInsnNode insn, PairValue value1, PairValue value2) throws AnalyzerException {
- return pair(
- left.binaryOperation(insn, value1.left, value2.left),
- right.binaryOperation(insn, value1.right, value2.right)
- );
- }
-
- @Override
- public PairValue ternaryOperation(AbstractInsnNode insn, PairValue value1, PairValue value2, PairValue value3) throws AnalyzerException {
- return pair(
- left.ternaryOperation(insn, value1.left, value2.left, value3.left),
- right.ternaryOperation(insn, value1.right, value2.right, value3.right)
- );
- }
-
- @Override
- public PairValue naryOperation(AbstractInsnNode insn, List extends PairValue> values) throws AnalyzerException {
- return pair(
- left.naryOperation(insn, values.stream().map(v -> v.left).toList()),
- right.naryOperation(insn, values.stream().map(v -> v.right).toList())
- );
- }
-
- @Override
- public void returnOperation(AbstractInsnNode insn, PairValue value, PairValue expected) throws AnalyzerException {
- left.returnOperation(insn, value.left, expected.left);
- right.returnOperation(insn, value.right, expected.right);
- }
-
- @Override
- public PairValue merge(PairValue value1, PairValue value2) {
- return pair(
- left.merge(value1.left, value2.left),
- right.merge(value1.right, value2.right)
- );
- }
-
- private PairValue pair(V left, W right) {
- if (left == null && right == null) {
- return null;
- }
-
- return new PairValue<>(left, right);
- }
-
- public static final class PairValue implements Value {
- public final V left;
- public final W right;
-
- public PairValue(V left, W right) {
- if (left == null && right == null) {
- throw new IllegalArgumentException("should use null rather than pair of nulls");
- }
-
- this.left = left;
- this.right = right;
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof InterpreterPair.PairValue pairValue && Objects.equals(left, pairValue.left) && Objects.equals(right, pairValue.right);
- }
-
- @Override
- public int hashCode() {
- return left.hashCode() * 31 + right.hashCode();
- }
-
- @Override
- public int getSize() {
- return (left == null ? right : left).getSize();
- }
- }
+ private final Interpreter left;
+ private final Interpreter right;
+
+ public InterpreterPair(Interpreter left, Interpreter right) {
+ super(Enigma.ASM_VERSION);
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public PairValue newValue(Type type) {
+ return pair(left.newValue(type), right.newValue(type));
+ }
+
+ @Override
+ public PairValue newOperation(AbstractInsnNode insn) throws AnalyzerException {
+ return pair(left.newOperation(insn), right.newOperation(insn));
+ }
+
+ @Override
+ public PairValue copyOperation(AbstractInsnNode insn, PairValue value) throws AnalyzerException {
+ return pair(left.copyOperation(insn, value.left), right.copyOperation(insn, value.right));
+ }
+
+ @Override
+ public PairValue unaryOperation(AbstractInsnNode insn, PairValue value) throws AnalyzerException {
+ return pair(left.unaryOperation(insn, value.left), right.unaryOperation(insn, value.right));
+ }
+
+ @Override
+ public PairValue binaryOperation(AbstractInsnNode insn, PairValue value1, PairValue value2) throws AnalyzerException {
+ return pair(left.binaryOperation(insn, value1.left, value2.left), right.binaryOperation(insn, value1.right, value2.right));
+ }
+
+ @Override
+ public PairValue ternaryOperation(AbstractInsnNode insn, PairValue value1, PairValue value2, PairValue value3) throws AnalyzerException {
+ return pair(left.ternaryOperation(insn, value1.left, value2.left, value3.left), right.ternaryOperation(insn, value1.right, value2.right, value3.right));
+ }
+
+ @Override
+ public PairValue naryOperation(AbstractInsnNode insn, List extends PairValue> values) throws AnalyzerException {
+ return pair(left.naryOperation(insn, values.stream().map(v -> v.left).toList()), right.naryOperation(insn, values.stream().map(v -> v.right).toList()));
+ }
+
+ @Override
+ public void returnOperation(AbstractInsnNode insn, PairValue value, PairValue expected) throws AnalyzerException {
+ left.returnOperation(insn, value.left, expected.left);
+ right.returnOperation(insn, value.right, expected.right);
+ }
+
+ @Override
+ public PairValue merge(PairValue value1, PairValue value2) {
+ return pair(left.merge(value1.left, value2.left), right.merge(value1.right, value2.right));
+ }
+
+ private PairValue pair(V left, W right) {
+ if (left == null && right == null) {
+ return null;
+ }
+
+ return new PairValue<>(left, right);
+ }
+
+ public static final class PairValue implements Value {
+ public final V left;
+ public final W right;
+
+ public PairValue(V left, W right) {
+ if (left == null && right == null) {
+ throw new IllegalArgumentException("should use null rather than pair of nulls");
+ }
+
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof InterpreterPair.PairValue pairValue && Objects.equals(left, pairValue.left) && Objects.equals(right, pairValue.right);
+ }
+
+ @Override
+ public int hashCode() {
+ return left.hashCode() * 31 + right.hashCode();
+ }
+
+ @Override
+ public int getSize() {
+ return (left == null ? right : left).getSize();
+ }
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
index 4633ace..83275da 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
@@ -1,17 +1,23 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis;
+import java.util.Collection;
+import java.util.List;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
import com.google.common.collect.Lists;
+
import cuchaz.enigma.analysis.index.EntryIndex;
import cuchaz.enigma.analysis.index.InheritanceIndex;
import cuchaz.enigma.analysis.index.JarIndex;
@@ -19,17 +25,13 @@ import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
-import javax.swing.tree.DefaultMutableTreeNode;
-import java.util.Collection;
-import java.util.List;
-
public class MethodImplementationsTreeNode extends DefaultMutableTreeNode {
-
private final Translator translator;
private MethodEntry entry;
public MethodImplementationsTreeNode(Translator translator, MethodEntry entry) {
this.translator = translator;
+
if (entry == null) {
throw new IllegalArgumentException("Entry cannot be null!");
}
@@ -46,10 +48,12 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode {
// recurse
for (int i = 0; i < node.getChildCount(); i++) {
MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode) node.getChildAt(i), entry);
+
if (foundNode != null) {
return foundNode;
}
}
+
return null;
}
@@ -70,8 +74,10 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode {
InheritanceIndex inheritanceIndex = index.getInheritanceIndex();
Collection descendants = inheritanceIndex.getDescendants(entry.getParent());
+
for (ClassEntry inheritor : descendants) {
MethodEntry methodEntry = entry.withParent(inheritor);
+
if (entryIndex.hasMethod(methodEntry)) {
nodes.add(new MethodImplementationsTreeNode(translator, methodEntry));
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
index 455456f..2afeed9 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
@@ -1,16 +1,18 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis;
+import javax.swing.tree.DefaultMutableTreeNode;
+
import cuchaz.enigma.analysis.index.EntryIndex;
import cuchaz.enigma.analysis.index.InheritanceIndex;
import cuchaz.enigma.analysis.index.JarIndex;
@@ -18,10 +20,7 @@ import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
-import javax.swing.tree.DefaultMutableTreeNode;
-
public class MethodInheritanceTreeNode extends DefaultMutableTreeNode {
-
private final Translator translator;
private MethodEntry entry;
private boolean implemented;
@@ -41,10 +40,12 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode {
// recurse
for (int i = 0; i < node.getChildCount(); i++) {
MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode) node.getChildAt(i), entry);
+
if (foundNode != null) {
return foundNode;
}
}
+
return null;
}
@@ -79,6 +80,7 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode {
InheritanceIndex inheritanceIndex = index.getInheritanceIndex();
boolean ret = false;
+
for (ClassEntry inheritorEntry : inheritanceIndex.getChildren(this.entry.getParent())) {
MethodEntry methodEntry = new MethodEntry(inheritorEntry, this.entry.getName(), this.entry.getDesc());
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java
index 8117103..8dc7fe6 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java
@@ -1,19 +1,19 @@
package cuchaz.enigma.analysis;
-import org.objectweb.asm.tree.MethodNode;
-
import java.util.function.Consumer;
+import org.objectweb.asm.tree.MethodNode;
+
public class MethodNodeWithAction extends MethodNode {
- private final Consumer action;
+ private final Consumer action;
- public MethodNodeWithAction(int api, int access, String name, String descriptor, String signature, String[] exceptions, Consumer action) {
- super(api, access, name, descriptor, signature, exceptions);
- this.action = action;
- }
+ public MethodNodeWithAction(int api, int access, String name, String descriptor, String signature, String[] exceptions, Consumer action) {
+ super(api, access, name, descriptor, signature, exceptions);
+ this.action = action;
+ }
- @Override
- public void visitEnd() {
- action.accept(this);
- }
+ @Override
+ public void visitEnd() {
+ action.accept(this);
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java
index 6803861..fc58c6d 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java
@@ -1,17 +1,25 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeNode;
+
import com.google.common.collect.Sets;
+
import cuchaz.enigma.analysis.index.JarIndex;
import cuchaz.enigma.analysis.index.ReferenceIndex;
import cuchaz.enigma.translation.Translator;
@@ -20,14 +28,7 @@ import cuchaz.enigma.translation.representation.entry.Entry;
import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.TreeNode;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Set;
-
public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode {
-
private final Translator translator;
private MethodEntry entry;
private EntryReference reference;
@@ -59,6 +60,7 @@ public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements R
if (this.reference != null) {
return String.format("%s", translator.translate(this.reference.context));
}
+
return translator.translate(this.entry).getName();
}
@@ -73,16 +75,18 @@ public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements R
if (recurse && this.children != null) {
for (Object child : this.children) {
if (child instanceof MethodReferenceTreeNode node) {
-
// don't recurse into ancestor
Set> ancestors = Sets.newHashSet();
TreeNode n = node;
+
while (n.getParent() != null) {
n = n.getParent();
+
if (n instanceof MethodReferenceTreeNode) {
ancestors.add(((MethodReferenceTreeNode) n).getEntry());
}
}
+
if (ancestors.contains(node.getEntry())) {
continue;
}
@@ -100,6 +104,7 @@ public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements R
Collection> references = new ArrayList<>();
EntryResolver entryResolver = index.getEntryResolver();
+
for (MethodEntry methodEntry : entryResolver.resolveEquivalentMethods(entry)) {
references.addAll(referenceIndex.getReferencesToMethod(methodEntry));
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java
index 5b19d18..4dcb834 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java
@@ -3,72 +3,72 @@ package cuchaz.enigma.analysis;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
public abstract class ReferenceTargetType {
- private static final None NONE = new None();
- private static final Uninitialized UNINITIALIZED = new Uninitialized();
-
- public abstract Kind getKind();
-
- public static None none() {
- return NONE;
- }
-
- public static Uninitialized uninitialized() {
- return UNINITIALIZED;
- }
-
- public static ClassType classType(ClassEntry name) {
- return new ClassType(name);
- }
-
- public enum Kind {
- NONE,
- UNINITIALIZED,
- CLASS_TYPE
- }
-
- public static class None extends ReferenceTargetType {
- @Override
- public Kind getKind() {
- return Kind.NONE;
- }
-
- @Override
- public String toString() {
- return "(none)";
- }
- }
-
- public static class Uninitialized extends ReferenceTargetType {
- @Override
- public Kind getKind() {
- return Kind.UNINITIALIZED;
- }
-
- @Override
- public String toString() {
- return "(uninitialized)";
- }
- }
-
- public static class ClassType extends ReferenceTargetType {
- private final ClassEntry entry;
-
- private ClassType(ClassEntry entry) {
- this.entry = entry;
- }
-
- public ClassEntry getEntry() {
- return entry;
- }
-
- @Override
- public Kind getKind() {
- return Kind.CLASS_TYPE;
- }
-
- @Override
- public String toString() {
- return entry.toString();
- }
- }
+ private static final None NONE = new None();
+ private static final Uninitialized UNINITIALIZED = new Uninitialized();
+
+ public abstract Kind getKind();
+
+ public static None none() {
+ return NONE;
+ }
+
+ public static Uninitialized uninitialized() {
+ return UNINITIALIZED;
+ }
+
+ public static ClassType classType(ClassEntry name) {
+ return new ClassType(name);
+ }
+
+ public enum Kind {
+ NONE,
+ UNINITIALIZED,
+ CLASS_TYPE
+ }
+
+ public static class None extends ReferenceTargetType {
+ @Override
+ public Kind getKind() {
+ return Kind.NONE;
+ }
+
+ @Override
+ public String toString() {
+ return "(none)";
+ }
+ }
+
+ public static class Uninitialized extends ReferenceTargetType {
+ @Override
+ public Kind getKind() {
+ return Kind.UNINITIALIZED;
+ }
+
+ @Override
+ public String toString() {
+ return "(uninitialized)";
+ }
+ }
+
+ public static class ClassType extends ReferenceTargetType {
+ private final ClassEntry entry;
+
+ private ClassType(ClassEntry entry) {
+ this.entry = entry;
+ }
+
+ public ClassEntry getEntry() {
+ return entry;
+ }
+
+ @Override
+ public Kind getKind() {
+ return Kind.CLASS_TYPE;
+ }
+
+ @Override
+ public String toString() {
+ return entry.toString();
+ }
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java
index ce23cb6..8e0afd5 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java
@@ -1,13 +1,13 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis;
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
index aea7618..b3ba896 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
@@ -1,180 +1,196 @@
package cuchaz.enigma.analysis;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
import cuchaz.enigma.EnigmaProject;
import cuchaz.enigma.api.service.NameProposalService;
import cuchaz.enigma.translation.TranslateResult;
import cuchaz.enigma.translation.mapping.EntryRemapper;
import cuchaz.enigma.translation.representation.AccessFlags;
import cuchaz.enigma.translation.representation.TypeDescriptor;
-import cuchaz.enigma.translation.representation.entry.*;
-
-import javax.swing.tree.DefaultMutableTreeNode;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.stream.Stream;
+import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
+import cuchaz.enigma.translation.representation.entry.ClassEntry;
+import cuchaz.enigma.translation.representation.entry.DefEntry;
+import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodEntry;
+import cuchaz.enigma.translation.representation.entry.ParentedEntry;
public class StructureTreeNode extends DefaultMutableTreeNode {
- private final List nameProposalServices;
- private final EntryRemapper mapper;
- private final ClassEntry parentEntry;
- private final ParentedEntry entry;
-
- public StructureTreeNode(EnigmaProject project, ClassEntry parentEntry, ParentedEntry entry) {
- this.nameProposalServices = project.getEnigma().getServices().get(NameProposalService.TYPE);
- this.mapper = project.getMapper();
- this.parentEntry = parentEntry;
- this.entry = entry;
- }
-
- /**
- * Returns the parented entry represented by this tree node.
- */
- public ParentedEntry getEntry() {
- return this.entry;
- }
-
- public void load(EnigmaProject project, StructureTreeOptions options) {
- Stream children = project.getJarIndex().getChildrenByClass().get(this.parentEntry).stream();
-
- children = switch (options.obfuscationVisibility()) {
- case ALL -> children;
- case OBFUSCATED -> children
- // remove deobfuscated members if only obfuscated, unless it's an inner class
- .filter(e -> (e instanceof ClassEntry) || (project.isObfuscated(e) && project.isRenamable(e)))
- // keep constructor methods if the class is obfuscated
- .filter(e -> !(e instanceof MethodEntry m && m.isConstructor()) || project.isObfuscated(e.getParent()));
- case DEOBFUSCATED -> children.filter(e -> (e instanceof ClassEntry)
- || (!project.isObfuscated(e) && project.isRenamable(e))
- // keep constructor methods if the class is deobfuscated
- || (e instanceof MethodEntry m && m.isConstructor()) && !project.isObfuscated(e.getParent()));
- };
-
- children = switch (options.documentationVisibility()) {
- case ALL -> children;
- // TODO remove EntryRemapper.deobfuscate() calls when javadocs will no longer be tied to deobfuscation
- case DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() != null && !project.getMapper().deobfuscate(e).getJavadocs().isBlank()));
- case NON_DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() == null || project.getMapper().deobfuscate(e).getJavadocs().isBlank()));
- };
-
- children = switch (options.sortingOrder()) {
- case DEFAULT -> children;
- case A_Z -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor())
- // compare the class name when the entry is a constructor
- ? project.getMapper().deobfuscate(e.getParent()).getSimpleName().toLowerCase()
- : project.getMapper().deobfuscate(e).getSimpleName().toLowerCase()));
- case Z_A -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor())
- ? project.getMapper().deobfuscate(((ParentedEntry>) e).getParent()).getSimpleName().toLowerCase()
- : project.getMapper().deobfuscate((ParentedEntry>) e).getSimpleName().toLowerCase())
- .reversed());
- };
-
- for (ParentedEntry> child : children.toList()) {
- StructureTreeNode childNode = new StructureTreeNode(project, this.parentEntry, child);
-
- if (child instanceof ClassEntry) {
- childNode = new StructureTreeNode(project, (ClassEntry) child, child);
- childNode.load(project, options);
- }
-
- this.add(childNode);
- }
- }
-
- @Override
- public String toString() {
- TranslateResult translateResult = this.mapper.extendedDeobfuscate(this.entry);
- String result = translateResult.getValue().getName();
-
- if (translateResult.isObfuscated()) {
- if (!this.nameProposalServices.isEmpty()) {
- for (NameProposalService service : this.nameProposalServices) {
- if (service.proposeName(this.entry, this.mapper).isPresent()) {
- result = service.proposeName(this.entry, this.mapper).get();
- }
- }
- }
- }
-
- if (this.entry instanceof FieldDefEntry) {
- FieldDefEntry field = (FieldDefEntry) translateResult.getValue();
- String returnType = this.parseDesc(field.getDesc());
-
- result = result + ": " + returnType;
- } else if (this.entry instanceof MethodDefEntry) {
- MethodDefEntry method = (MethodDefEntry) translateResult.getValue();
- String args = this.parseArgs(method.getDesc().getArgumentDescs());
- String returnType = this.parseDesc(method.getDesc().getReturnDesc());
-
- if (method.isConstructor()) {
- result = method.getParent().getSimpleName() + args;
- } else {
- result = result + args + ": " + returnType;
- }
- }
-
- return result;
- }
-
- public String toHtml() {
- List modifiers = new ArrayList<>();
-
- if (this.entry instanceof DefEntry> defEntry) {
- AccessFlags access = defEntry.getAccess();
- boolean isInterfaceMethod = false;
-
- if (this.entry instanceof MethodEntry && this.entry.getParent() instanceof ClassDefEntry parent) {
- isInterfaceMethod = parent.getAccess().isInterface();
- }
-
- if (access.isStatic() && !access.isEnum()) {
- // Static member, but not an enum constant
- modifiers.add("static");
- } else if (isInterfaceMethod && !access.isAbstract()) {
- // Non-static default interface method
- modifiers.add("default");
- }
-
- if (access.isAbstract() && !access.isInterface() && !isInterfaceMethod && !access.isEnum()) {
- // Abstract, but not an interface, an interface method or an enum class (abstract is the default or meaningless)
- modifiers.add("abstract");
- } else if (access.isFinal() && !access.isEnum()) {
- // Final, but not an enum or an enum constant (they're always final)
- modifiers.add("final");
- }
- }
-
- return "" + String.join(" ", modifiers) + " " + toString();
- }
-
- private String parseArgs(List args) {
- if (args.size() > 0) {
- String result = "(";
-
- for (int i = 0; i < args.size(); i++) {
- if (i > 0) {
- result += ", ";
- }
-
- result += this.parseDesc(args.get(i));
- }
-
- return result + ")";
- }
-
- return "()";
- }
-
- private String parseDesc(TypeDescriptor desc) {
- if (desc.isVoid()) return "void";
- if (desc.isPrimitive()) return desc.getPrimitive().getKeyword();
- if (desc.isType()) return desc.getTypeEntry().getSimpleName();
-
- if (desc.isArray()) {
- if (desc.getArrayType().isPrimitive()) return desc.getArrayType().getPrimitive().getKeyword() + "[]";
- if (desc.getArrayType().isType()) return desc.getArrayType().getTypeEntry().getSimpleName() + "[]";
- }
-
- return null;
- }
+ private final List nameProposalServices;
+ private final EntryRemapper mapper;
+ private final ClassEntry parentEntry;
+ private final ParentedEntry entry;
+
+ public StructureTreeNode(EnigmaProject project, ClassEntry parentEntry, ParentedEntry entry) {
+ this.nameProposalServices = project.getEnigma().getServices().get(NameProposalService.TYPE);
+ this.mapper = project.getMapper();
+ this.parentEntry = parentEntry;
+ this.entry = entry;
+ }
+
+ /**
+ * Returns the parented entry represented by this tree node.
+ */
+ public ParentedEntry getEntry() {
+ return this.entry;
+ }
+
+ public void load(EnigmaProject project, StructureTreeOptions options) {
+ Stream children = project.getJarIndex().getChildrenByClass().get(this.parentEntry).stream();
+
+ children = switch (options.obfuscationVisibility()) {
+ case ALL -> children;
+ case OBFUSCATED -> children
+ // remove deobfuscated members if only obfuscated, unless it's an inner class
+ .filter(e -> (e instanceof ClassEntry) || (project.isObfuscated(e) && project.isRenamable(e)))
+ // keep constructor methods if the class is obfuscated
+ .filter(e -> !(e instanceof MethodEntry m && m.isConstructor()) || project.isObfuscated(e.getParent()));
+ case DEOBFUSCATED -> children.filter(e -> (e instanceof ClassEntry) || (!project.isObfuscated(e) && project.isRenamable(e))
+ // keep constructor methods if the class is deobfuscated
+ || (e instanceof MethodEntry m && m.isConstructor()) && !project.isObfuscated(e.getParent()));
+ };
+
+ children = switch (options.documentationVisibility()) {
+ case ALL -> children;
+ // TODO remove EntryRemapper.deobfuscate() calls when javadocs will no longer be tied to deobfuscation
+ case DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() != null && !project.getMapper().deobfuscate(e).getJavadocs().isBlank()));
+ case NON_DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() == null || project.getMapper().deobfuscate(e).getJavadocs().isBlank()));
+ };
+
+ children = switch (options.sortingOrder()) {
+ case DEFAULT -> children;
+ case A_Z -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor())
+ // compare the class name when the entry is a constructor
+ ? project.getMapper().deobfuscate(e.getParent()).getSimpleName().toLowerCase() : project.getMapper().deobfuscate(e).getSimpleName().toLowerCase()));
+ case Z_A -> children.sorted(
+ Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor()) ? project.getMapper().deobfuscate(((ParentedEntry>) e).getParent()).getSimpleName().toLowerCase() : project.getMapper().deobfuscate((ParentedEntry>) e).getSimpleName().toLowerCase()).reversed());
+ };
+
+ for (ParentedEntry> child : children.toList()) {
+ StructureTreeNode childNode = new StructureTreeNode(project, this.parentEntry, child);
+
+ if (child instanceof ClassEntry) {
+ childNode = new StructureTreeNode(project, (ClassEntry) child, child);
+ childNode.load(project, options);
+ }
+
+ this.add(childNode);
+ }
+ }
+
+ @Override
+ public String toString() {
+ TranslateResult translateResult = this.mapper.extendedDeobfuscate(this.entry);
+ String result = translateResult.getValue().getName();
+
+ if (translateResult.isObfuscated()) {
+ if (!this.nameProposalServices.isEmpty()) {
+ for (NameProposalService service : this.nameProposalServices) {
+ if (service.proposeName(this.entry, this.mapper).isPresent()) {
+ result = service.proposeName(this.entry, this.mapper).get();
+ }
+ }
+ }
+ }
+
+ if (this.entry instanceof FieldDefEntry) {
+ FieldDefEntry field = (FieldDefEntry) translateResult.getValue();
+ String returnType = this.parseDesc(field.getDesc());
+
+ result = result + ": " + returnType;
+ } else if (this.entry instanceof MethodDefEntry) {
+ MethodDefEntry method = (MethodDefEntry) translateResult.getValue();
+ String args = this.parseArgs(method.getDesc().getArgumentDescs());
+ String returnType = this.parseDesc(method.getDesc().getReturnDesc());
+
+ if (method.isConstructor()) {
+ result = method.getParent().getSimpleName() + args;
+ } else {
+ result = result + args + ": " + returnType;
+ }
+ }
+
+ return result;
+ }
+
+ public String toHtml() {
+ List modifiers = new ArrayList<>();
+
+ if (this.entry instanceof DefEntry> defEntry) {
+ AccessFlags access = defEntry.getAccess();
+ boolean isInterfaceMethod = false;
+
+ if (this.entry instanceof MethodEntry && this.entry.getParent() instanceof ClassDefEntry parent) {
+ isInterfaceMethod = parent.getAccess().isInterface();
+ }
+
+ if (access.isStatic() && !access.isEnum()) {
+ // Static member, but not an enum constant
+ modifiers.add("static");
+ } else if (isInterfaceMethod && !access.isAbstract()) {
+ // Non-static default interface method
+ modifiers.add("default");
+ }
+
+ if (access.isAbstract() && !access.isInterface() && !isInterfaceMethod && !access.isEnum()) {
+ // Abstract, but not an interface, an interface method or an enum class (abstract is the default or meaningless)
+ modifiers.add("abstract");
+ } else if (access.isFinal() && !access.isEnum()) {
+ // Final, but not an enum or an enum constant (they're always final)
+ modifiers.add("final");
+ }
+ }
+
+ return "" + String.join(" ", modifiers) + " " + toString();
+ }
+
+ private String parseArgs(List args) {
+ if (args.size() > 0) {
+ String result = "(";
+
+ for (int i = 0; i < args.size(); i++) {
+ if (i > 0) {
+ result += ", ";
+ }
+
+ result += this.parseDesc(args.get(i));
+ }
+
+ return result + ")";
+ }
+
+ return "()";
+ }
+
+ private String parseDesc(TypeDescriptor desc) {
+ if (desc.isVoid()) {
+ return "void";
+ }
+
+ if (desc.isPrimitive()) {
+ return desc.getPrimitive().getKeyword();
+ }
+
+ if (desc.isType()) {
+ return desc.getTypeEntry().getSimpleName();
+ }
+
+ if (desc.isArray()) {
+ if (desc.getArrayType().isPrimitive()) {
+ return desc.getArrayType().getPrimitive().getKeyword() + "[]";
+ }
+
+ if (desc.getArrayType().isType()) {
+ return desc.getArrayType().getTypeEntry().getSimpleName() + "[]";
+ }
+ }
+
+ return null;
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java
index cfc80b4..e2e5084 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java
@@ -1,59 +1,55 @@
package cuchaz.enigma.analysis;
-public record StructureTreeOptions(
- ObfuscationVisibility obfuscationVisibility,
- DocumentationVisibility documentationVisibility,
- SortingOrder sortingOrder) {
-
- public enum ObfuscationVisibility implements Option {
- ALL("structure.options.obfuscation.all"),
- OBFUSCATED("structure.options.obfuscation.obfuscated"),
- DEOBFUSCATED("structure.options.obfuscation.deobfuscated");
-
- private final String translationKey;
-
- ObfuscationVisibility(String translationKey) {
- this.translationKey = translationKey;
- }
-
- public String getTranslationKey() {
- return this.translationKey;
- }
- }
-
- public enum DocumentationVisibility implements Option {
- ALL("structure.options.documentation.all"),
- DOCUMENTED("structure.options.documentation.documented"),
- NON_DOCUMENTED("structure.options.documentation.non_documented");
-
- private final String translationKey;
-
- DocumentationVisibility(String translationKey) {
- this.translationKey = translationKey;
- }
-
- public String getTranslationKey() {
- return this.translationKey;
- }
- }
-
- public enum SortingOrder implements Option {
- DEFAULT("structure.options.sorting.default"),
- A_Z("structure.options.sorting.a_z"),
- Z_A("structure.options.sorting.z_a");
-
- private final String translationKey;
-
- SortingOrder(String translationKey) {
- this.translationKey = translationKey;
- }
-
- public String getTranslationKey() {
- return this.translationKey;
- }
- }
-
- public interface Option {
- String getTranslationKey();
- }
+public record StructureTreeOptions(ObfuscationVisibility obfuscationVisibility, DocumentationVisibility documentationVisibility, SortingOrder sortingOrder) {
+ public enum ObfuscationVisibility implements Option {
+ ALL("structure.options.obfuscation.all"),
+ OBFUSCATED("structure.options.obfuscation.obfuscated"),
+ DEOBFUSCATED("structure.options.obfuscation.deobfuscated");
+
+ private final String translationKey;
+
+ ObfuscationVisibility(String translationKey) {
+ this.translationKey = translationKey;
+ }
+
+ public String getTranslationKey() {
+ return this.translationKey;
+ }
+ }
+
+ public enum DocumentationVisibility implements Option {
+ ALL("structure.options.documentation.all"),
+ DOCUMENTED("structure.options.documentation.documented"),
+ NON_DOCUMENTED("structure.options.documentation.non_documented");
+
+ private final String translationKey;
+
+ DocumentationVisibility(String translationKey) {
+ this.translationKey = translationKey;
+ }
+
+ public String getTranslationKey() {
+ return this.translationKey;
+ }
+ }
+
+ public enum SortingOrder implements Option {
+ DEFAULT("structure.options.sorting.default"),
+ A_Z("structure.options.sorting.a_z"),
+ Z_A("structure.options.sorting.z_a");
+
+ private final String translationKey;
+
+ SortingOrder(String translationKey) {
+ this.translationKey = translationKey;
+ }
+
+ public String getTranslationKey() {
+ return this.translationKey;
+ }
+ }
+
+ public interface Option {
+ String getTranslationKey();
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java
index a4b1aac..26093c3 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java
@@ -1,6 +1,15 @@
package cuchaz.enigma.analysis.index;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
import com.google.common.collect.Maps;
+
import cuchaz.enigma.translation.representation.AccessFlags;
import cuchaz.enigma.translation.representation.MethodDescriptor;
import cuchaz.enigma.translation.representation.TypeDescriptor;
@@ -8,9 +17,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
-import javax.annotation.Nullable;
-import java.util.*;
-
public class BridgeMethodIndex implements JarIndexer {
private final EntryIndex entryIndex;
private final InheritanceIndex inheritanceIndex;
@@ -31,6 +37,7 @@ public class BridgeMethodIndex implements JarIndexer {
MethodDefEntry methodDefEntry = (MethodDefEntry) methodEntry;
AccessFlags access = methodDefEntry.getAccess();
+
if (access == null || !access.isSynthetic()) {
continue;
}
@@ -46,6 +53,7 @@ public class BridgeMethodIndex implements JarIndexer {
for (Map.Entry entry : copiedAccessToBridge.entrySet()) {
MethodEntry specializedEntry = entry.getKey();
MethodEntry bridgeEntry = entry.getValue();
+
if (bridgeEntry.getName().equals(specializedEntry.getName())) {
continue;
}
@@ -57,6 +65,7 @@ public class BridgeMethodIndex implements JarIndexer {
private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) {
MethodEntry specializedMethod = findSpecializedMethod(syntheticMethod);
+
if (specializedMethod == null) {
return;
}
@@ -84,6 +93,7 @@ public class BridgeMethodIndex implements JarIndexer {
private boolean isPotentialBridge(MethodDefEntry bridgeMethod, MethodEntry specializedMethod) {
// Bridge methods only exist for inheritance purposes, if we're private, final, or static, we cannot be inherited
AccessFlags bridgeAccess = bridgeMethod.getAccess();
+
if (bridgeAccess.isPrivate() || bridgeAccess.isFinal() || bridgeAccess.isStatic()) {
return false;
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java
index bb992b7..0e4cdcf 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java
@@ -1,13 +1,21 @@
package cuchaz.enigma.analysis.index;
-import cuchaz.enigma.translation.representation.AccessFlags;
-import cuchaz.enigma.translation.representation.entry.*;
-
-import javax.annotation.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import javax.annotation.Nullable;
+
+import cuchaz.enigma.translation.representation.AccessFlags;
+import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
+import cuchaz.enigma.translation.representation.entry.ClassEntry;
+import cuchaz.enigma.translation.representation.entry.Entry;
+import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
+import cuchaz.enigma.translation.representation.entry.FieldEntry;
+import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodEntry;
+
public class EntryIndex implements JarIndexer {
private Map classes = new HashMap<>();
private Map fields = new HashMap<>();
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java
index f9cb23c..e697182 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java
@@ -1,12 +1,13 @@
package cuchaz.enigma.analysis.index;
-import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
-import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
-import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
+import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
+import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
+
public class IndexClassVisitor extends ClassVisitor {
private final JarIndexer indexer;
private ClassDefEntry classEntry;
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java
index efea83d..97fec47 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java
@@ -1,5 +1,22 @@
package cuchaz.enigma.analysis.index;
+import java.util.List;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.FieldInsnNode;
+import org.objectweb.asm.tree.InvokeDynamicInsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.analysis.Analyzer;
+import org.objectweb.asm.tree.analysis.AnalyzerException;
+import org.objectweb.asm.tree.analysis.BasicValue;
+import org.objectweb.asm.tree.analysis.SourceInterpreter;
+import org.objectweb.asm.tree.analysis.SourceValue;
+
import cuchaz.enigma.analysis.IndexSimpleVerifier;
import cuchaz.enigma.analysis.InterpreterPair;
import cuchaz.enigma.analysis.MethodNodeWithAction;
@@ -8,15 +25,11 @@ import cuchaz.enigma.translation.representation.AccessFlags;
import cuchaz.enigma.translation.representation.Lambda;
import cuchaz.enigma.translation.representation.MethodDescriptor;
import cuchaz.enigma.translation.representation.Signature;
-import cuchaz.enigma.translation.representation.entry.*;
-import org.objectweb.asm.*;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.FieldInsnNode;
-import org.objectweb.asm.tree.InvokeDynamicInsnNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.analysis.*;
-
-import java.util.List;
+import cuchaz.enigma.translation.representation.entry.ClassEntry;
+import cuchaz.enigma.translation.representation.entry.FieldEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodEntry;
+import cuchaz.enigma.translation.representation.entry.ParentedEntry;
public class IndexReferenceVisitor extends ClassVisitor {
private final JarIndexer indexer;
@@ -54,7 +67,7 @@ public class IndexReferenceVisitor extends ClassVisitor {
private final MethodDefEntry callerEntry;
private JarIndexer indexer;
- public MethodInterpreter(MethodDefEntry callerEntry, JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex) {
+ MethodInterpreter(MethodDefEntry callerEntry, JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex) {
super(new IndexSimpleVerifier(entryIndex, inheritanceIndex), new SourceInterpreter());
this.callerEntry = callerEntry;
this.indexer = indexer;
@@ -85,7 +98,6 @@ public class IndexReferenceVisitor extends ClassVisitor {
return super.unaryOperation(insn, value);
}
-
@Override
public PairValue binaryOperation(AbstractInsnNode insn, PairValue value1, PairValue value2) throws AnalyzerException {
if (insn.getOpcode() == Opcodes.PUTFIELD) {
@@ -119,6 +131,7 @@ public class IndexReferenceVisitor extends ClassVisitor {
Type instantiatedMethodType = (Type) invokeDynamicInsn.bsmArgs[2];
ReferenceTargetType targetType;
+
if (implMethod.getTag() != Opcodes.H_GETSTATIC && implMethod.getTag() != Opcodes.H_PUTFIELD && implMethod.getTag() != Opcodes.H_INVOKESTATIC) {
if (instantiatedMethodType.getArgumentTypes().length < Type.getArgumentTypes(implMethod.getDesc()).length) {
targetType = getReferenceTargetType(values.get(0), insn);
@@ -129,13 +142,7 @@ public class IndexReferenceVisitor extends ClassVisitor {
targetType = ReferenceTargetType.none();
}
- indexer.indexLambda(callerEntry, new Lambda(
- invokeDynamicInsn.name,
- new MethodDescriptor(invokeDynamicInsn.desc),
- new MethodDescriptor(samMethodType.getDescriptor()),
- getHandleEntry(implMethod),
- new MethodDescriptor(instantiatedMethodType.getDescriptor())
- ), targetType);
+ indexer.indexLambda(callerEntry, new Lambda(invokeDynamicInsn.name, new MethodDescriptor(invokeDynamicInsn.desc), new MethodDescriptor(samMethodType.getDescriptor()), getHandleEntry(implMethod), new MethodDescriptor(instantiatedMethodType.getDescriptor())), targetType);
}
}
@@ -160,17 +167,17 @@ public class IndexReferenceVisitor extends ClassVisitor {
private static ParentedEntry> getHandleEntry(Handle handle) {
switch (handle.getTag()) {
- case Opcodes.H_GETFIELD:
- case Opcodes.H_GETSTATIC:
- case Opcodes.H_PUTFIELD:
- case Opcodes.H_PUTSTATIC:
- return FieldEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc());
- case Opcodes.H_INVOKEINTERFACE:
- case Opcodes.H_INVOKESPECIAL:
- case Opcodes.H_INVOKESTATIC:
- case Opcodes.H_INVOKEVIRTUAL:
- case Opcodes.H_NEWINVOKESPECIAL:
- return MethodEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc());
+ case Opcodes.H_GETFIELD:
+ case Opcodes.H_GETSTATIC:
+ case Opcodes.H_PUTFIELD:
+ case Opcodes.H_PUTSTATIC:
+ return FieldEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc());
+ case Opcodes.H_INVOKEINTERFACE:
+ case Opcodes.H_INVOKESPECIAL:
+ case Opcodes.H_INVOKESTATIC:
+ case Opcodes.H_INVOKEVIRTUAL:
+ case Opcodes.H_NEWINVOKESPECIAL:
+ return MethodEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc());
}
throw new RuntimeException("Invalid handle tag " + handle.getTag());
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java
index 1ab2abd..1c60db9 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java
@@ -1,27 +1,28 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis.index;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
+
import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.Set;
-
public class InheritanceIndex implements JarIndexer {
private final EntryIndex entryIndex;
@@ -39,6 +40,7 @@ public class InheritanceIndex implements JarIndexer {
}
ClassEntry superClass = classEntry.getSuperClass();
+
if (superClass != null && !superClass.getName().equals("java/lang/Object")) {
indexParent(classEntry, superClass);
}
@@ -96,8 +98,13 @@ public class InheritanceIndex implements JarIndexer {
}
public Relation computeClassRelation(ClassEntry classEntry, ClassEntry potentialAncestor) {
- if (potentialAncestor.getName().equals("java/lang/Object")) return Relation.RELATED;
- if (!entryIndex.hasClass(classEntry)) return Relation.UNKNOWN;
+ if (potentialAncestor.getName().equals("java/lang/Object")) {
+ return Relation.RELATED;
+ }
+
+ if (!entryIndex.hasClass(classEntry)) {
+ return Relation.UNKNOWN;
+ }
for (ClassEntry ancestor : getAncestors(classEntry)) {
if (potentialAncestor.equals(ancestor)) {
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
index 6c26282..60864ba 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
@@ -1,17 +1,26 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.analysis.index;
-import com.google.common.collect.*;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Multimap;
+
import cuchaz.enigma.Enigma;
import cuchaz.enigma.ProgressListener;
import cuchaz.enigma.analysis.ReferenceTargetType;
@@ -19,11 +28,15 @@ import cuchaz.enigma.classprovider.ClassProvider;
import cuchaz.enigma.translation.mapping.EntryResolver;
import cuchaz.enigma.translation.mapping.IndexEntryResolver;
import cuchaz.enigma.translation.representation.Lambda;
-import cuchaz.enigma.translation.representation.entry.*;
+import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
+import cuchaz.enigma.translation.representation.entry.ClassEntry;
+import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
+import cuchaz.enigma.translation.representation.entry.FieldEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodEntry;
+import cuchaz.enigma.translation.representation.entry.ParentedEntry;
import cuchaz.enigma.utils.I18n;
-import java.util.*;
-
public class JarIndex implements JarIndexer {
private final Set indexedClasses = new HashSet<>();
private final EntryIndex entryIndex;
@@ -99,6 +112,7 @@ public class JarIndex implements JarIndexer {
}
indexers.forEach(indexer -> indexer.indexClass(classEntry));
+
if (classEntry.isInnerClass() && !classEntry.getAccess().isSynthetic()) {
childrenByClass.put(classEntry.getParent(), classEntry);
}
@@ -111,6 +125,7 @@ public class JarIndex implements JarIndexer {
}
indexers.forEach(indexer -> indexer.indexField(fieldEntry));
+
if (!fieldEntry.getAccess().isSynthetic()) {
childrenByClass.put(fieldEntry.getParent(), fieldEntry);
}
@@ -123,6 +138,7 @@ public class JarIndex implements JarIndexer {
}
indexers.forEach(indexer -> indexer.indexMethod(methodEntry));
+
if (!methodEntry.getAccess().isSynthetic() && !methodEntry.getName().equals("")) {
childrenByClass.put(methodEntry.getParent(), methodEntry);
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java
index f17e7c9..8726fb5 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java
@@ -2,7 +2,11 @@ package cuchaz.enigma.analysis.index;
import cuchaz.enigma.analysis.ReferenceTargetType;
import cuchaz.enigma.translation.representation.Lambda;
-import cuchaz.enigma.translation.representation.entry.*;
+import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
+import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
+import cuchaz.enigma.translation.representation.entry.FieldEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodEntry;
public interface JarIndexer {
default void indexClass(ClassDefEntry classEntry) {
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java
index 64de5f3..b400a66 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java
@@ -1,15 +1,25 @@
package cuchaz.enigma.analysis.index;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+
import cuchaz.enigma.analysis.EntryReference;
import cuchaz.enigma.analysis.ReferenceTargetType;
import cuchaz.enigma.translation.representation.AccessFlags;
-import cuchaz.enigma.translation.representation.entry.*;
-
-import java.util.*;
+import cuchaz.enigma.translation.representation.entry.ClassEntry;
+import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
+import cuchaz.enigma.translation.representation.entry.FieldEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodEntry;
public class PackageVisibilityIndex implements JarIndexer {
private static boolean requiresSamePackage(AccessFlags entryAcc, EntryReference ref, InheritanceIndex inheritanceIndex) {
@@ -30,9 +40,7 @@ public class PackageVisibilityIndex implements JarIndexer {
}
// access to instance member only valid if target's class assignable to context class
- return !(ref.targetType.getKind() == ReferenceTargetType.Kind.UNINITIALIZED ||
- ((ReferenceTargetType.ClassType) ref.targetType).getEntry().equals(contextClass) ||
- inheritanceIndex.getAncestors(((ReferenceTargetType.ClassType) ref.targetType).getEntry()).contains(contextClass));
+ return !(ref.targetType.getKind() == ReferenceTargetType.Kind.UNINITIALIZED || ((ReferenceTargetType.ClassType) ref.targetType).getEntry().equals(contextClass) || inheritanceIndex.getAncestors(((ReferenceTargetType.ClassType) ref.targetType).getEntry()).contains(contextClass));
}
return true;
@@ -61,6 +69,7 @@ public class PackageVisibilityIndex implements JarIndexer {
private void addConnections(EntryIndex entryIndex, ReferenceIndex referenceIndex, InheritanceIndex inheritanceIndex) {
for (FieldEntry entry : entryIndex.getFields()) {
AccessFlags entryAcc = entryIndex.getFieldAccess(entry);
+
if (!entryAcc.isPublic() && !entryAcc.isPrivate()) {
for (EntryReference ref : referenceIndex.getReferencesToField(entry)) {
if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) {
@@ -72,6 +81,7 @@ public class PackageVisibilityIndex implements JarIndexer {
for (MethodEntry entry : entryIndex.getMethods()) {
AccessFlags entryAcc = entryIndex.getMethodAccess(entry);
+
if (!entryAcc.isPublic() && !entryAcc.isPrivate()) {
for (EntryReference ref : referenceIndex.getReferencesToMethod(entry)) {
if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) {
@@ -83,6 +93,7 @@ public class PackageVisibilityIndex implements JarIndexer {
for (ClassEntry entry : entryIndex.getClasses()) {
AccessFlags entryAcc = entryIndex.getClassAccess(entry);
+
if (!entryAcc.isPublic() && !entryAcc.isPrivate()) {
for (EntryReference ref : referenceIndex.getFieldTypeReferencesToClass(entry)) {
if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) {
@@ -99,12 +110,14 @@ public class PackageVisibilityIndex implements JarIndexer {
for (ClassEntry parent : inheritanceIndex.getParents(entry)) {
AccessFlags parentAcc = entryIndex.getClassAccess(parent);
+
if (parentAcc != null && !parentAcc.isPublic() && !parentAcc.isPrivate()) {
addConnection(entry, parent);
}
}
ClassEntry outerClass = entry.getOuterClass();
+
if (outerClass != null) {
addConnection(entry, outerClass);
}
@@ -113,6 +126,7 @@ public class PackageVisibilityIndex implements JarIndexer {
private void addPartitions(EntryIndex entryIndex) {
Set unassignedClasses = Sets.newHashSet(entryIndex.getClasses());
+
while (!unassignedClasses.isEmpty()) {
Iterator iterator = unassignedClasses.iterator();
ClassEntry initialEntry = iterator.next();
@@ -122,6 +136,7 @@ public class PackageVisibilityIndex implements JarIndexer {
partition.add(initialEntry);
buildPartition(unassignedClasses, partition, initialEntry);
partitions.add(partition);
+
for (ClassEntry entry : partition) {
classPartitions.put(entry, partition);
}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java
index b6797c2..332a967 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java
@@ -1,17 +1,23 @@
package cuchaz.enigma.analysis.index;
+import java.util.Collection;
+import java.util.Map;
+
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
+
import cuchaz.enigma.analysis.EntryReference;
import cuchaz.enigma.analysis.ReferenceTargetType;
import cuchaz.enigma.translation.mapping.ResolutionStrategy;
import cuchaz.enigma.translation.representation.Lambda;
import cuchaz.enigma.translation.representation.MethodDescriptor;
import cuchaz.enigma.translation.representation.TypeDescriptor;
-import cuchaz.enigma.translation.representation.entry.*;
-
-import java.util.Collection;
-import java.util.Map;
+import cuchaz.enigma.translation.representation.entry.ClassEntry;
+import cuchaz.enigma.translation.representation.entry.Entry;
+import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
+import cuchaz.enigma.translation.representation.entry.FieldEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodEntry;
public class ReferenceIndex implements JarIndexer {
private Multimap methodReferences = HashMultimap.create();
@@ -24,13 +30,14 @@ public class ReferenceIndex implements JarIndexer {
@Override
public void indexMethod(MethodDefEntry methodEntry) {
- indexMethodDescriptor(methodEntry, methodEntry.getDesc());
+ indexMethodDescriptor(methodEntry, methodEntry.getDesc());
}
private void indexMethodDescriptor(MethodDefEntry entry, MethodDescriptor descriptor) {
for (TypeDescriptor typeDescriptor : descriptor.getArgumentDescs()) {
indexMethodTypeDescriptor(entry, typeDescriptor);
}
+
indexMethodTypeDescriptor(entry, descriptor.getReturnDesc());
}
@@ -45,7 +52,7 @@ public class ReferenceIndex implements JarIndexer {
@Override
public void indexField(FieldDefEntry fieldEntry) {
- indexFieldTypeDescriptor(fieldEntry, fieldEntry.getDesc());
+ indexFieldTypeDescriptor(fieldEntry, fieldEntry.getDesc());
}
private void indexFieldTypeDescriptor(FieldDefEntry field, TypeDescriptor typeDescriptor) {
@@ -53,7 +60,7 @@ public class ReferenceIndex implements JarIndexer {
ClassEntry referencedClass = typeDescriptor.getTypeEntry();
fieldTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), field));
} else if (typeDescriptor.isArray()) {
- indexFieldTypeDescriptor(field, typeDescriptor.getArrayType());
+ indexFieldTypeDescriptor(field, typeDescriptor.getArrayType());
}
}
@@ -99,18 +106,22 @@ public class ReferenceIndex implements JarIndexer {
private , V extends Entry>> Multimap remapReferences(JarIndex index, Multimap multimap) {
final int keySetSize = multimap.keySet().size();
Multimap resolved = HashMultimap.create(multimap.keySet().size(), keySetSize == 0 ? 0 : multimap.size() / keySetSize);
+
for (Map.Entry entry : multimap.entries()) {
resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue()));
}
+
return resolved;
}
private , C extends Entry>> Multimap> remapReferencesTo(JarIndex index, Multimap> multimap) {
final int keySetSize = multimap.keySet().size();
Multimap> resolved = HashMultimap.create(keySetSize, keySetSize == 0 ? 0 : multimap.size() / keySetSize);
+
for (Map.Entry> entry : multimap.entries()) {
resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue()));
}
+
return resolved;
}
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java b/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java
index 358828f..e2cb6b1 100644
--- a/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java
+++ b/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java
@@ -18,7 +18,9 @@ public final class EnigmaServiceType {
@Override
public boolean equals(Object obj) {
- if (obj == this) return true;
+ if (obj == this) {
+ return true;
+ }
if (obj instanceof EnigmaServiceType) {
return ((EnigmaServiceType) obj).key.equals(key);
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java b/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java
index 5417531..3ed6d33 100644
--- a/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java
+++ b/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java
@@ -1,10 +1,11 @@
package cuchaz.enigma.api.service;
-import cuchaz.enigma.analysis.index.JarIndex;
-import cuchaz.enigma.classprovider.ClassProvider;
+import java.util.Set;
+
import org.objectweb.asm.ClassVisitor;
-import java.util.Set;
+import cuchaz.enigma.analysis.index.JarIndex;
+import cuchaz.enigma.classprovider.ClassProvider;
public interface JarIndexerService extends EnigmaService {
EnigmaServiceType TYPE = EnigmaServiceType.create("jar_indexer");
@@ -12,7 +13,7 @@ public interface JarIndexerService extends EnigmaService {
void acceptJar(Set scope, ClassProvider classProvider, JarIndex jarIndex);
static JarIndexerService fromVisitor(ClassVisitor visitor) {
- return (scope, classProvider, jarIndex) -> {
+ return (scope, classProvider, jarIndex) -> {
for (String className : scope) {
classProvider.get(className).accept(visitor);
}
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java b/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java
index 4c357db..4c40868 100644
--- a/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java
+++ b/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java
@@ -1,10 +1,10 @@
package cuchaz.enigma.api.service;
+import java.util.Optional;
+
import cuchaz.enigma.translation.mapping.EntryRemapper;
import cuchaz.enigma.translation.representation.entry.Entry;
-import java.util.Optional;
-
public interface NameProposalService extends EnigmaService {
EnigmaServiceType TYPE = EnigmaServiceType.create("name_proposal");
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java
index 341cfce..891fe9d 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java
@@ -1,32 +1,34 @@
package cuchaz.enigma.bytecode.translators;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.representation.MethodDescriptor;
import cuchaz.enigma.translation.representation.TypeDescriptor;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.translation.representation.entry.FieldEntry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
-import org.objectweb.asm.Handle;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
public class AsmObjectTranslator {
public static Type translateType(Translator translator, Type type) {
String descString = type.getDescriptor();
switch (type.getSort()) {
- case Type.OBJECT: {
- ClassEntry classEntry = new ClassEntry(type.getInternalName());
- return Type.getObjectType(translator.translate(classEntry).getFullName());
- }
- case Type.ARRAY: {
- TypeDescriptor descriptor = new TypeDescriptor(descString);
- return Type.getType(translator.translate(descriptor).toString());
- }
- case Type.METHOD: {
- MethodDescriptor descriptor = new MethodDescriptor(descString);
- return Type.getMethodType(translator.translate(descriptor).toString());
- }
+ case Type.OBJECT: {
+ ClassEntry classEntry = new ClassEntry(type.getInternalName());
+ return Type.getObjectType(translator.translate(classEntry).getFullName());
+ }
+ case Type.ARRAY: {
+ TypeDescriptor descriptor = new TypeDescriptor(descString);
+ return Type.getType(translator.translate(descriptor).toString());
+ }
+ case Type.METHOD: {
+ MethodDescriptor descriptor = new MethodDescriptor(descString);
+ return Type.getMethodType(translator.translate(descriptor).toString());
}
+ }
+
return type;
}
@@ -55,6 +57,7 @@ public class AsmObjectTranslator {
} else if (value instanceof Handle) {
return translateHandle(translator, (Handle) value);
}
+
return value;
}
}
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java
index cfd8fbe..dc399e5 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java
@@ -1,18 +1,19 @@
package cuchaz.enigma.bytecode.translators;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import com.google.common.base.CharMatcher;
-import cuchaz.enigma.translation.LocalNameGenerator;
-import cuchaz.enigma.translation.representation.TypeDescriptor;
-import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
-import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import cuchaz.enigma.translation.LocalNameGenerator;
+import cuchaz.enigma.translation.representation.TypeDescriptor;
+import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
public class LocalVariableFixVisitor extends ClassVisitor {
private ClassDefEntry ownerEntry;
@@ -46,6 +47,7 @@ public class LocalVariableFixVisitor extends ClassVisitor {
int lvIndex = methodEntry.getAccess().isStatic() ? 0 : 1;
List parameters = methodEntry.getDesc().getArgumentDescs();
+
for (int parameterIndex = 0; parameterIndex < parameters.size(); parameterIndex++) {
TypeDescriptor param = parameters.get(parameterIndex);
parameterIndices.put(lvIndex, parameterIndex);
@@ -81,6 +83,7 @@ public class LocalVariableFixVisitor extends ClassVisitor {
public void visitEnd() {
if (!hasParameterTable) {
List arguments = methodEntry.getDesc().getArgumentDescs();
+
for (int argumentIndex = 0; argumentIndex < arguments.size(); argumentIndex++) {
super.visitParameter(fixParameterName(argumentIndex, null), fixParameterAccess(argumentIndex, 0));
}
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java
index 2b750ea..51b21a6 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java
@@ -1,12 +1,13 @@
package cuchaz.enigma.bytecode.translators;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
import cuchaz.enigma.analysis.index.BridgeMethodIndex;
import cuchaz.enigma.analysis.index.JarIndex;
import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
public class SourceFixVisitor extends ClassVisitor {
private final JarIndex index;
@@ -28,6 +29,7 @@ public class SourceFixVisitor extends ClassVisitor {
MethodDefEntry methodEntry = MethodDefEntry.parse(ownerEntry, access, name, descriptor, signature);
BridgeMethodIndex bridgeIndex = index.getBridgeMethodIndex();
+
if (bridgeIndex.isBridgeMethod(methodEntry)) {
access |= Opcodes.ACC_BRIDGE;
} else if (bridgeIndex.isSpecializedMethod(methodEntry)) {
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java
index cb843ad..d105e4c 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java
@@ -1,10 +1,11 @@
package cuchaz.enigma.bytecode.translators;
+import org.objectweb.asm.AnnotationVisitor;
+
import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.representation.TypeDescriptor;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.translation.representation.entry.FieldEntry;
-import org.objectweb.asm.AnnotationVisitor;
public class TranslationAnnotationVisitor extends AnnotationVisitor {
private final Translator translator;
@@ -29,6 +30,7 @@ public class TranslationAnnotationVisitor extends AnnotationVisitor {
@Override
public AnnotationVisitor visitAnnotation(String name, String desc) {
TypeDescriptor type = new TypeDescriptor(desc);
+
if (name != null) {
FieldEntry annotationField = translator.translate(new FieldEntry(annotationEntry, name, type));
return super.visitAnnotation(annotationField.getName(), annotationField.getDesc().toString());
@@ -41,6 +43,7 @@ public class TranslationAnnotationVisitor extends AnnotationVisitor {
public void visitEnum(String name, String desc, String value) {
TypeDescriptor type = new TypeDescriptor(desc);
FieldEntry enumField = translator.translate(new FieldEntry(type.getTypeEntry(), value, type));
+
if (name != null) {
FieldEntry annotationField = translator.translate(new FieldEntry(annotationEntry, name, type));
super.visitEnum(annotationField.getName(), annotationField.getDesc().toString(), enumField.getName());
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java
index 0b2ca9a..66c8490 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java
@@ -1,23 +1,33 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.bytecode.translators;
+import java.util.Arrays;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.RecordComponentVisitor;
+import org.objectweb.asm.TypePath;
+
import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.representation.MethodDescriptor;
import cuchaz.enigma.translation.representation.TypeDescriptor;
-import cuchaz.enigma.translation.representation.entry.*;
-import org.objectweb.asm.*;
-
-import java.util.Arrays;
+import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
+import cuchaz.enigma.translation.representation.entry.ClassEntry;
+import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodEntry;
public class TranslationClassVisitor extends ClassVisitor {
private final Translator translator;
@@ -53,9 +63,11 @@ public class TranslationClassVisitor extends ClassVisitor {
MethodDefEntry entry = MethodDefEntry.parse(obfClassEntry, access, name, desc, signature);
MethodDefEntry translatedEntry = translator.translate(entry);
String[] translatedExceptions = new String[exceptions.length];
+
for (int i = 0; i < exceptions.length; i++) {
translatedExceptions[i] = translator.translate(new ClassEntry(exceptions[i])).getFullName();
}
+
MethodVisitor mv = super.visitMethod(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), translatedEntry.getSignature().toString(), translatedExceptions);
return new TranslationMethodVisitor(translator, obfClassEntry, entry, api, mv);
}
@@ -65,6 +77,7 @@ public class TranslationClassVisitor extends ClassVisitor {
ClassDefEntry classEntry = ClassDefEntry.parse(access, name, obfClassEntry.getSignature().toString(), null, new String[0]);
ClassDefEntry translatedEntry = translator.translate(classEntry);
ClassEntry translatedOuterClass = translatedEntry.getOuterClass();
+
if (translatedOuterClass == null) {
throw new IllegalStateException("Translated inner class did not have outer class");
}
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java
index 28fc199..d026f15 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java
@@ -1,12 +1,13 @@
package cuchaz.enigma.bytecode.translators;
-import cuchaz.enigma.translation.Translator;
-import cuchaz.enigma.translation.representation.TypeDescriptor;
-import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.TypePath;
+import cuchaz.enigma.translation.Translator;
+import cuchaz.enigma.translation.representation.TypeDescriptor;
+import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
+
public class TranslationFieldVisitor extends FieldVisitor {
private final FieldDefEntry fieldEntry;
private final Translator translator;
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java
index a82df1b..932c123 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java
@@ -1,11 +1,21 @@
package cuchaz.enigma.bytecode.translators;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.TypePath;
+
import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.representation.MethodDescriptor;
import cuchaz.enigma.translation.representation.Signature;
import cuchaz.enigma.translation.representation.TypeDescriptor;
-import cuchaz.enigma.translation.representation.entry.*;
-import org.objectweb.asm.*;
+import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
+import cuchaz.enigma.translation.representation.entry.ClassEntry;
+import cuchaz.enigma.translation.representation.entry.FieldEntry;
+import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
+import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
+import cuchaz.enigma.translation.representation.entry.MethodEntry;
public class TranslationMethodVisitor extends MethodVisitor {
private final MethodDefEntry methodEntry;
@@ -55,13 +65,16 @@ public class TranslationMethodVisitor extends MethodVisitor {
if (array == null) {
return null;
}
+
for (int i = 0; i < count; i++) {
Object object = array[i];
+
if (object instanceof String) {
String type = (String) object;
array[i] = translator.translate(new ClassEntry(type)).getFullName();
}
}
+
return array;
}
@@ -96,9 +109,11 @@ public class TranslationMethodVisitor extends MethodVisitor {
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
MethodDescriptor translatedMethodDesc = translator.translate(new MethodDescriptor(desc));
Object[] translatedBsmArgs = new Object[bsmArgs.length];
+
for (int i = 0; i < bsmArgs.length; i++) {
translatedBsmArgs[i] = AsmObjectTranslator.translateValue(translator, bsmArgs[i]);
}
+
super.visitInvokeDynamicInsn(name, translatedMethodDesc.toString(), AsmObjectTranslator.translateHandle(translator, bsm), translatedBsmArgs);
}
@@ -132,7 +147,7 @@ public class TranslationMethodVisitor extends MethodVisitor {
}
private String translateVariableName(int index, String name) {
- LocalVariableEntry entry = new LocalVariableEntry(methodEntry, index, "", true,null);
+ LocalVariableEntry entry = new LocalVariableEntry(methodEntry, index, "", true, null);
LocalVariableEntry translatedEntry = translator.translate(entry);
String translatedName = translatedEntry.getName();
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java
index 06fd22b..f7de0f8 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java
@@ -1,11 +1,12 @@
package cuchaz.enigma.bytecode.translators;
-import cuchaz.enigma.translation.Translator;
-import cuchaz.enigma.translation.representation.TypeDescriptor;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.RecordComponentVisitor;
import org.objectweb.asm.TypePath;
+import cuchaz.enigma.translation.Translator;
+import cuchaz.enigma.translation.representation.TypeDescriptor;
+
public class TranslationRecordComponentVisitor extends RecordComponentVisitor {
private final Translator translator;
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java
index 6cab22c..49350f6 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java
@@ -29,17 +29,23 @@ public class TranslationSignatureVisitor extends SignatureVisitor {
@Override
public void visitInnerClassType(String name) {
String lastClass = classStack.pop();
- if (!name.startsWith(lastClass+"$")){//todo see if there's a way to base this on whether there were type params or not
- name = lastClass+"$"+name;
+
+ if (!name.startsWith(lastClass + "$")) {
+ //todo see if there's a way to base this on whether there were type params or not
+ name = lastClass + "$" + name;
}
+
classStack.push(name);
String translatedEntry = this.remapper.apply(name);
- if (translatedEntry.contains("/")){
- translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("/")+1);
+
+ if (translatedEntry.contains("/")) {
+ translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("/") + 1);
}
- if (translatedEntry.contains("$")){
- translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("$")+1);
+
+ if (translatedEntry.contains("$")) {
+ translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("$") + 1);
}
+
this.sv.visitInnerClassType(translatedEntry);
}
@@ -120,8 +126,10 @@ public class TranslationSignatureVisitor extends SignatureVisitor {
@Override
public void visitEnd() {
this.sv.visitEnd();
- if (!classStack.empty())
+
+ if (!classStack.empty()) {
classStack.pop();
+ }
}
@Override
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java
index 326197d..2a1643e 100644
--- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java
+++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java
@@ -18,7 +18,6 @@ import cuchaz.enigma.utils.Result;
* @see ClassHandleProvider
*/
public interface ClassHandle extends AutoCloseable {
-
/**
* Gets the reference to this class. This is always obfuscated, for example
* {@code net/minecraft/class_1000}.
@@ -104,5 +103,4 @@ public interface ClassHandle extends AutoCloseable {
*/
@Override
void close();
-
}
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java
index 20f847a..ce6b23f 100644
--- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java
+++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java
@@ -6,7 +6,6 @@ import java.io.PrintStream;
import javax.annotation.Nullable;
public final class ClassHandleError {
-
public final Type type;
public final Throwable cause;
@@ -17,7 +16,10 @@ public final class ClassHandleError {
@Nullable
public String getStackTrace() {
- if (cause == null) return null;
+ if (cause == null) {
+ return null;
+ }
+
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(os);
cause.printStackTrace(ps);
@@ -36,5 +38,4 @@ public final class ClassHandleError {
DECOMPILE,
REMAP,
}
-
-}
\ No newline at end of file
+}
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
index 229d18a..f18be67 100644
--- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
@@ -1,6 +1,15 @@
package cuchaz.enigma.classhandle;
-import java.util.*;
+import static cuchaz.enigma.utils.Utils.withLock;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -16,14 +25,16 @@ import cuchaz.enigma.classprovider.CachingClassProvider;
import cuchaz.enigma.classprovider.ObfuscationFixClassProvider;
import cuchaz.enigma.events.ClassHandleListener;
import cuchaz.enigma.events.ClassHandleListener.InvalidationType;
-import cuchaz.enigma.source.*;
+import cuchaz.enigma.source.DecompiledClassSource;
+import cuchaz.enigma.source.Decompiler;
+import cuchaz.enigma.source.DecompilerService;
+import cuchaz.enigma.source.Source;
+import cuchaz.enigma.source.SourceIndex;
+import cuchaz.enigma.source.SourceSettings;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.utils.Result;
-import static cuchaz.enigma.utils.Utils.withLock;
-
public final class ClassHandleProvider {
-
private final EnigmaProject project;
private final ExecutorService pool = Executors.newWorkStealingPool();
@@ -50,7 +61,9 @@ public final class ClassHandleProvider {
*/
@Nullable
public ClassHandle openClass(ClassEntry entry) {
- if (!project.getJarIndex().getEntryIndex().hasClass(entry)) return null;
+ if (!project.getJarIndex().getEntryIndex().hasClass(entry)) {
+ return null;
+ }
return withLock(lock.writeLock(), () -> {
Entry e = handles.computeIfAbsent(entry, entry1 -> new Entry(this, entry1));
@@ -68,7 +81,9 @@ public final class ClassHandleProvider {
* @param ds the decompiler service to use
*/
public void setDecompilerService(DecompilerService ds) {
- if (this.ds.equals(ds)) return;
+ if (this.ds.equals(ds)) {
+ return;
+ }
this.ds = ds;
this.decompiler = createDecompiler();
@@ -111,6 +126,7 @@ public final class ClassHandleProvider {
public void invalidateMapped(ClassEntry entry) {
withLock(lock.readLock(), () -> {
Entry e = handles.get(entry);
+
if (e != null) {
e.invalidateMapped();
}
@@ -136,6 +152,7 @@ public final class ClassHandleProvider {
public void invalidateJavadoc(ClassEntry entry) {
withLock(lock.readLock(), () -> {
Entry e = handles.get(entry);
+
if (e != null) {
e.invalidateJavadoc();
}
@@ -163,6 +180,7 @@ public final class ClassHandleProvider {
*/
public void destroy() {
pool.shutdown();
+
try {
pool.awaitTermination(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
@@ -176,7 +194,6 @@ public final class ClassHandleProvider {
}
private static final class Entry {
-
private final ClassHandleProvider p;
private final ClassEntry entry;
private ClassEntry deobfRef;
@@ -216,6 +233,7 @@ public final class ClassHandleProvider {
private void checkDeobfRefForUpdate() {
ClassEntry newDeobf = p.project.getMapper().deobfuscate(entry);
+
if (!Objects.equals(deobfRef, newDeobf)) {
deobfRef = newDeobf;
// copy the list so we don't call event listener code with the lock active
@@ -244,7 +262,9 @@ public final class ClassHandleProvider {
private CompletableFuture> decompile() {
int v = decompileVersion.incrementAndGet();
return CompletableFuture.supplyAsync(() -> {
- if (decompileVersion.get() != v) return null;
+ if (decompileVersion.get() != v) {
+ return null;
+ }
Result uncommentedSource = Result.ok(p.decompiler.getSource(entry.getFullName()));
Entry.this.uncommentedSource = uncommentedSource;
@@ -258,7 +278,10 @@ public final class ClassHandleProvider {
private CompletableFuture> continueInsertJavadoc(CompletableFuture> f) {
int v = javadocVersion.incrementAndGet();
return f.thenApplyAsync(res -> {
- if (res == null || javadocVersion.get() != v) return null;
+ if (res == null || javadocVersion.get() != v) {
+ return null;
+ }
+
Result jdSource = res.map(s -> s.withJavadocs(p.project.getMapper()));
withLock(lock.readLock(), () -> new ArrayList<>(handles)).forEach(h -> h.onDocsChanged(jdSource));
return jdSource;
@@ -268,7 +291,10 @@ public final class ClassHandleProvider {
private CompletableFuture> continueIndexSource(CompletableFuture> f) {
int v = indexVersion.incrementAndGet();
return f.thenApplyAsync(res -> {
- if (res == null || indexVersion.get() != v) return null;
+ if (res == null || indexVersion.get() != v) {
+ return null;
+ }
+
return res.andThen(jdSource -> {
SourceIndex index = jdSource.index();
index.resolveReferences(p.project.getMapper().getObfResolver());
@@ -281,11 +307,20 @@ public final class ClassHandleProvider {
private void continueMapSource(CompletableFuture> f) {
int v = mappedVersion.incrementAndGet();
f.thenApplyAsync(res -> {
- if (res == null || mappedVersion.get() != v) return null;
+ if (res == null || mappedVersion.get() != v) {
+ return null;
+ }
+
return res.andThen(source -> Result.ok(source.remapSource(p.project, p.project.getMapper().getDeobfuscator())));
}, p.pool).whenComplete((res, e) -> {
- if (e != null) res = Result.err(ClassHandleError.remap(e));
- if (res == null) return;
+ if (e != null) {
+ res = Result.err(ClassHandleError.remap(e));
+ }
+
+ if (res == null) {
+ return;
+ }
+
Entry.this.source = res;
Entry.this.waitingSources.forEach(s -> s.complete(source));
Entry.this.waitingSources.clear();
@@ -297,6 +332,7 @@ public final class ClassHandleProvider {
classHandle.destroy();
withLock(lock.writeLock(), () -> {
handles.remove(classHandle);
+
if (handles.isEmpty()) {
p.deleteEntry(this);
}
@@ -332,7 +368,6 @@ public final class ClassHandleProvider {
}
private static final class ClassHandleImpl implements ClassHandle {
-
private final Entry entry;
private boolean valid = true;
@@ -425,18 +460,20 @@ public final class ClassHandleProvider {
@Override
public void close() {
- if (valid) entry.closeHandle(this);
+ if (valid) {
+ entry.closeHandle(this);
+ }
}
private void checkValid() {
- if (!valid) throw new IllegalStateException("Class handle no longer valid");
+ if (!valid) {
+ throw new IllegalStateException("Class handle no longer valid");
+ }
}
public void destroy() {
listeners.forEach(l -> l.onDeleted(this));
valid = false;
}
-
}
-
}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java
index 47f5eb8..eaba6df 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java
@@ -1,36 +1,33 @@
package cuchaz.enigma.classprovider;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import org.objectweb.asm.tree.ClassNode;
-
-import javax.annotation.Nullable;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+import javax.annotation.Nullable;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import org.objectweb.asm.tree.ClassNode;
+
/**
* Wraps a ClassProvider to provide caching and synchronization.
*/
public class CachingClassProvider implements ClassProvider {
- private final ClassProvider classProvider;
- private final Cache> cache = CacheBuilder.newBuilder()
- .maximumSize(128)
- .expireAfterAccess(1, TimeUnit.MINUTES)
- .concurrencyLevel(1)
- .build();
+ private final ClassProvider classProvider;
+ private final Cache> cache = CacheBuilder.newBuilder().maximumSize(128).expireAfterAccess(1, TimeUnit.MINUTES).concurrencyLevel(1).build();
- public CachingClassProvider(ClassProvider classProvider) {
- this.classProvider = classProvider;
- }
+ public CachingClassProvider(ClassProvider classProvider) {
+ this.classProvider = classProvider;
+ }
- @Override
- @Nullable
- public ClassNode get(String name) {
- try {
- return cache.get(name, () -> Optional.ofNullable(classProvider.get(name))).orElse(null);
- } catch (ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
+ @Override
+ @Nullable
+ public ClassNode get(String name) {
+ try {
+ return cache.get(name, () -> Optional.ofNullable(classProvider.get(name))).orElse(null);
+ } catch (ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java
index 6e4a665..6eec0f3 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java
@@ -1,17 +1,17 @@
package cuchaz.enigma.classprovider;
-import org.objectweb.asm.tree.ClassNode;
-
import javax.annotation.Nullable;
+import org.objectweb.asm.tree.ClassNode;
+
public interface ClassProvider {
- /**
- * Gets the {@linkplain ClassNode} for a class. The class provider may return a cached result,
- * so it's important to not mutate it.
- *
- * @param name the internal name of the class
- * @return the {@linkplain ClassNode} for that class, or {@code null} if it was not found
- */
- @Nullable
- ClassNode get(String name);
+ /**
+ * Gets the {@linkplain ClassNode} for a class. The class provider may return a cached result,
+ * so it's important to not mutate it.
+ *
+ * @param name the internal name of the class
+ * @return the {@linkplain ClassNode} for that class, or {@code null} if it was not found
+ */
+ @Nullable
+ ClassNode get(String name);
}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java
index e9472fa..224093f 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java
@@ -1,27 +1,30 @@
package cuchaz.enigma.classprovider;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.tree.ClassNode;
-
-import javax.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream;
+import javax.annotation.Nullable;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.tree.ClassNode;
+
/**
* Provides classes by loading them from the classpath.
*/
public class ClasspathClassProvider implements ClassProvider {
- @Nullable @Override public ClassNode get(String name) {
- try (InputStream in = ClasspathClassProvider.class.getResourceAsStream("/" + name + ".class")) {
- if (in == null) {
- return null;
- }
+ @Nullable
+ @Override
+ public ClassNode get(String name) {
+ try (InputStream in = ClasspathClassProvider.class.getResourceAsStream("/" + name + ".class")) {
+ if (in == null) {
+ return null;
+ }
- ClassNode node = new ClassNode();
- new ClassReader(in).accept(node, 0);
- return node;
- } catch (IOException e) {
- return null;
- }
- }
+ ClassNode node = new ClassNode();
+ new ClassReader(in).accept(node, 0);
+ return node;
+ } catch (IOException e) {
+ return null;
+ }
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java
index 865464c..6856540 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java
@@ -1,31 +1,31 @@
package cuchaz.enigma.classprovider;
-import org.objectweb.asm.tree.ClassNode;
-
import javax.annotation.Nullable;
+import org.objectweb.asm.tree.ClassNode;
+
/**
* Combines a list of {@link ClassProvider}s into one, calling each one in a row
* until one can provide the class.
*/
public class CombiningClassProvider implements ClassProvider {
- private final ClassProvider[] classProviders;
+ private final ClassProvider[] classProviders;
- public CombiningClassProvider(ClassProvider... classProviders) {
- this.classProviders = classProviders;
- }
+ public CombiningClassProvider(ClassProvider... classProviders) {
+ this.classProviders = classProviders;
+ }
- @Override
- @Nullable
- public ClassNode get(String name) {
- for (ClassProvider cp : classProviders) {
- ClassNode node = cp.get(name);
+ @Override
+ @Nullable
+ public ClassNode get(String name) {
+ for (ClassProvider cp : classProviders) {
+ ClassNode node = cp.get(name);
- if (node != null) {
- return node;
- }
- }
+ if (node != null) {
+ return node;
+ }
+ }
- return null;
- }
+ return null;
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java
index c614b0a..900a0c8 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java
@@ -1,10 +1,5 @@
package cuchaz.enigma.classprovider;
-import com.google.common.collect.ImmutableSet;
-import cuchaz.enigma.utils.AsmUtil;
-import org.objectweb.asm.tree.ClassNode;
-
-import javax.annotation.Nullable;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
@@ -12,53 +7,60 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Set;
+import javax.annotation.Nullable;
+
+import com.google.common.collect.ImmutableSet;
+import org.objectweb.asm.tree.ClassNode;
+
+import cuchaz.enigma.utils.AsmUtil;
+
/**
* Provides classes by loading them from a JAR file.
*/
public class JarClassProvider implements AutoCloseable, ClassProvider {
- private final FileSystem fileSystem;
- private final Set classNames;
+ private final FileSystem fileSystem;
+ private final Set classNames;
+
+ public JarClassProvider(Path jarPath) throws IOException {
+ this.fileSystem = FileSystems.newFileSystem(jarPath, (ClassLoader) null);
+ this.classNames = collectClassNames(fileSystem);
+ }
- public JarClassProvider(Path jarPath) throws IOException {
- this.fileSystem = FileSystems.newFileSystem(jarPath, (ClassLoader) null);
- this.classNames = collectClassNames(fileSystem);
- }
+ private static ImmutableSet collectClassNames(FileSystem fileSystem) throws IOException {
+ ImmutableSet.Builder classNames = ImmutableSet.builder();
- private static ImmutableSet collectClassNames(FileSystem fileSystem) throws IOException {
- ImmutableSet.Builder classNames = ImmutableSet.builder();
- for (Path root : fileSystem.getRootDirectories()) {
- Files.walk(root).map(Path::toString)
- .forEach(path -> {
- if (path.endsWith(".class")) {
- String name = path.substring(1, path.length() - ".class".length());
- classNames.add(name);
- }
- });
- }
+ for (Path root : fileSystem.getRootDirectories()) {
+ Files.walk(root).map(Path::toString).forEach(path -> {
+ if (path.endsWith(".class")) {
+ String name = path.substring(1, path.length() - ".class".length());
+ classNames.add(name);
+ }
+ });
+ }
- return classNames.build();
- }
+ return classNames.build();
+ }
- public Set getClassNames() {
- return classNames;
- }
+ public Set getClassNames() {
+ return classNames;
+ }
- @Nullable
- @Override
- public ClassNode get(String name) {
- if (!classNames.contains(name)) {
- return null;
- }
+ @Nullable
+ @Override
+ public ClassNode get(String name) {
+ if (!classNames.contains(name)) {
+ return null;
+ }
- try {
- return AsmUtil.bytesToNode(Files.readAllBytes(fileSystem.getPath(name + ".class")));
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
+ try {
+ return AsmUtil.bytesToNode(Files.readAllBytes(fileSystem.getPath(name + ".class")));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
- @Override
- public void close() throws Exception {
- fileSystem.close();
- }
+ @Override
+ public void close() throws Exception {
+ fileSystem.close();
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java
index 36236a8..604bf49 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java
@@ -1,10 +1,7 @@
package cuchaz.enigma.classprovider;
-import cuchaz.enigma.Enigma;
-import cuchaz.enigma.analysis.index.JarIndex;
-import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor;
-import cuchaz.enigma.bytecode.translators.SourceFixVisitor;
-import cuchaz.enigma.classprovider.ClassProvider;
+import javax.annotation.Nullable;
+
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
@@ -12,7 +9,10 @@ import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
-import javax.annotation.Nullable;
+import cuchaz.enigma.Enigma;
+import cuchaz.enigma.analysis.index.JarIndex;
+import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor;
+import cuchaz.enigma.bytecode.translators.SourceFixVisitor;
/**
* Wraps a ClassProvider to apply fixes to the following problems introduced by the obfuscator,
@@ -26,59 +26,63 @@ import javax.annotation.Nullable;
*
Enum constructor parameters that are incorrectly named or missing the "synthetic" access modifier
*
"this" parameter which is incorrectly named
*
- *
- * These fixes are only applied to classes that were indexed by the JarIndex provided, and not library classes.
+ *
+ *
These fixes are only applied to classes that were indexed by the JarIndex provided, and not library classes.
*/
public class ObfuscationFixClassProvider implements ClassProvider {
- private final ClassProvider classProvider;
- private final JarIndex jarIndex;
+ private final ClassProvider classProvider;
+ private final JarIndex jarIndex;
+
+ public ObfuscationFixClassProvider(ClassProvider classProvider, JarIndex jarIndex) {
+ this.classProvider = classProvider;
+ this.jarIndex = jarIndex;
+ }
+
+ @Override
+ @Nullable
+ public ClassNode get(String name) {
+ ClassNode node = classProvider.get(name);
+
+ if (!jarIndex.isIndexed(name)) {
+ return node;
+ }
- public ObfuscationFixClassProvider(ClassProvider classProvider, JarIndex jarIndex) {
- this.classProvider = classProvider;
- this.jarIndex = jarIndex;
- }
+ ClassNode fixedNode = new ClassNode();
+ ClassVisitor visitor = fixedNode;
+ visitor = new LocalVariableFixVisitor(Enigma.ASM_VERSION, visitor);
+ visitor = new SourceFixVisitor(Enigma.ASM_VERSION, visitor, jarIndex);
+ node.accept(visitor);
+ removeRedundantClassCalls(fixedNode);
- @Override
- @Nullable
- public ClassNode get(String name) {
- ClassNode node = classProvider.get(name);
+ return fixedNode;
+ }
- if (!jarIndex.isIndexed(name)) {
- return node;
- }
+ private void removeRedundantClassCalls(ClassNode node) {
+ // Removes .getClass() calls added by Proguard:
+ // DUP
+ // INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
+ // POP
+ for (MethodNode methodNode : node.methods) {
+ AbstractInsnNode insnNode = methodNode.instructions.getFirst();
- ClassNode fixedNode = new ClassNode();
- ClassVisitor visitor = fixedNode;
- visitor = new LocalVariableFixVisitor(Enigma.ASM_VERSION, visitor);
- visitor = new SourceFixVisitor(Enigma.ASM_VERSION, visitor, jarIndex);
- node.accept(visitor);
- removeRedundantClassCalls(fixedNode);
+ while (insnNode != null) {
+ if (insnNode instanceof MethodInsnNode methodInsnNode && insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) {
+ if (methodInsnNode.name.equals("getClass") && methodInsnNode.owner.equals("java/lang/Object") && methodInsnNode.desc.equals("()Ljava/lang/Class;")) {
+ AbstractInsnNode previous = methodInsnNode.getPrevious();
+ AbstractInsnNode next = methodInsnNode.getNext();
- return fixedNode;
- }
+ if (previous.getOpcode() == Opcodes.DUP && next.getOpcode() == Opcodes.POP) {
+ //reset the iterator so it gets the new next instruction
+ insnNode = previous.getPrevious();
+ methodNode.instructions.remove(previous);
+ methodNode.instructions.remove(methodInsnNode);
+ methodNode.instructions.remove(next);
+ }
+ }
+ }
- private void removeRedundantClassCalls(ClassNode node) {
- // Removes .getClass() calls added by Proguard:
- // DUP
- // INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
- // POP
- for (MethodNode methodNode : node.methods) {
- AbstractInsnNode insnNode = methodNode.instructions.getFirst();
- while (insnNode != null) {
- if (insnNode instanceof MethodInsnNode methodInsnNode && insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) {
- if (methodInsnNode.name.equals("getClass") && methodInsnNode.owner.equals("java/lang/Object") && methodInsnNode.desc.equals("()Ljava/lang/Class;")) {
- AbstractInsnNode previous = methodInsnNode.getPrevious();
- AbstractInsnNode next = methodInsnNode.getNext();
- if (previous.getOpcode() == Opcodes.DUP && next.getOpcode() == Opcodes.POP) {
- insnNode = previous.getPrevious();//reset the iterator so it gets the new next instruction
- methodNode.instructions.remove(previous);
- methodNode.instructions.remove(methodInsnNode);
- methodNode.instructions.remove(next);
- }
- }
- }
- insnNode = insnNode.getNext();
- }
- }
- }
+ insnNode = insnNode.getNext();
+ }
+ }
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java
index cb9cbc2..fd078a2 100644
--- a/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java
+++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java
@@ -8,7 +8,6 @@ import java.util.Deque;
import java.util.LinkedList;
public class ConfigContainer {
-
private Path configPath;
private boolean existsOnDisk;
@@ -19,7 +18,10 @@ public class ConfigContainer {
}
public void save() {
- if (this.configPath == null) throw new IllegalStateException("File has no config path set!");
+ if (this.configPath == null) {
+ throw new IllegalStateException("File has no config path set!");
+ }
+
try {
Files.createDirectories(this.configPath.getParent());
Files.write(this.configPath, this.serialize().getBytes(StandardCharsets.UTF_8));
@@ -52,6 +54,7 @@ public class ConfigContainer {
public static ConfigContainer getOrCreate(Path path) {
ConfigContainer cc = null;
+
try {
if (Files.exists(path)) {
String s = String.join("\n", Files.readAllLines(path));
@@ -93,5 +96,4 @@ public class ConfigContainer {
});
return cc;
}
-
}
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java
index b3f3d0c..6d9d304 100644
--- a/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java
+++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java
@@ -6,7 +6,6 @@ import java.nio.file.Paths;
import cuchaz.enigma.utils.Os;
public class ConfigPaths {
-
public static Path getConfigFilePath(String name) {
String fileName = Os.getOs() == Os.LINUX ? String.format("%src", name) : String.format("%s.ini", name);
return getConfigPathRoot().resolve(fileName);
@@ -14,27 +13,30 @@ public class ConfigPaths {
public static Path getConfigPathRoot() {
switch (Os.getOs()) {
- case LINUX:
- String configHome = System.getenv("XDG_CONFIG_HOME");
- if (configHome == null) {
- return getUserHomeUnix().resolve(".config");
- }
- return Paths.get(configHome);
- case MAC:
- return getUserHomeUnix().resolve("Library").resolve("Application Support");
- case WINDOWS:
- return Paths.get(System.getenv("LOCALAPPDATA"));
- default:
- return Paths.get(System.getProperty("user.dir"));
+ case LINUX:
+ String configHome = System.getenv("XDG_CONFIG_HOME");
+
+ if (configHome == null) {
+ return getUserHomeUnix().resolve(".config");
+ }
+
+ return Paths.get(configHome);
+ case MAC:
+ return getUserHomeUnix().resolve("Library").resolve("Application Support");
+ case WINDOWS:
+ return Paths.get(System.getenv("LOCALAPPDATA"));
+ default:
+ return Paths.get(System.getProperty("user.dir"));
}
}
private static Path getUserHomeUnix() {
String userHome = System.getenv("HOME");
+
if (userHome == null) {
userHome = System.getProperty("user.dir");
}
+
return Paths.get(userHome);
}
-
}
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java
index 3e7bf6d..fba7da3 100644
--- a/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java
+++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java
@@ -1,10 +1,16 @@
package cuchaz.enigma.config;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
import java.util.function.Function;
public class ConfigSection {
-
private final Map values;
private final Map sections;
@@ -163,11 +169,16 @@ public class ConfigSection {
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ConfigSection)) return false;
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof ConfigSection)) {
+ return false;
+ }
+
ConfigSection that = (ConfigSection) o;
- return values.equals(that.values) &&
- sections.equals(that.sections);
+ return values.equals(that.values) && sections.equals(that.sections);
}
@Override
@@ -179,5 +190,4 @@ public class ConfigSection {
public String toString() {
return String.format("ConfigSection { values: %s, sections: %s }", values, sections);
}
-
}
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java
index dccb585..a1e3e55 100644
--- a/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java
+++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java
@@ -1,13 +1,17 @@
package cuchaz.enigma.config;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public final class ConfigSerializer {
-
private static final Pattern FULL_RGB_COLOR = Pattern.compile("#[0-9A-Fa-f]{6}");
private static final Pattern MIN_RGB_COLOR = Pattern.compile("#[0-9A-Fa-f]{3}");
@@ -19,6 +23,7 @@ public final class ConfigSerializer {
// join escaped newlines
int len = lines.length;
+
for (int i = len - 2; i >= 0; i--) {
if (lines[i].endsWith("\\")) {
lines[i] = String.format("%s\n%s", lines[i], lines[i + 1]);
@@ -31,24 +36,30 @@ public final class ConfigSerializer {
String line = lines[i];
// skip empty lines and comment lines
- if (line.trim().isEmpty() || line.trim().startsWith(";")) continue;
+ if (line.trim().isEmpty() || line.trim().startsWith(";")) {
+ continue;
+ }
int r;
- boolean fail = (r = parseSectionLine(line, 0, visitor)) == NO_MATCH &&
- (r = parseKeyValue(line, 0, visitor)) == NO_MATCH;
+ boolean fail = (r = parseSectionLine(line, 0, visitor)) == NO_MATCH && (r = parseKeyValue(line, 0, visitor)) == NO_MATCH;
}
}
private static int parseSectionLine(String v, int idx, ConfigStructureVisitor visitor) {
if (v.startsWith("[")) {
List path = new ArrayList<>();
+
while (idx < v.length() && v.charAt(idx) == '[') {
idx = parseSection(v, idx, path);
- if (idx == UNEXPECTED_TOKEN) return UNEXPECTED_TOKEN;
+
+ if (idx == UNEXPECTED_TOKEN) {
+ return UNEXPECTED_TOKEN;
+ }
}
if (!path.isEmpty()) {
visitor.jumpToRootSection();
+
for (String s : path) {
visitor.visitSection(s);
}
@@ -63,10 +74,12 @@ public final class ConfigSerializer {
private static int parseSection(String v, int idx, List path) {
idx += 1; // skip leading [
StringBuilder sb = new StringBuilder();
+
while (idx < v.length()) {
int nextCloseBracket = v.indexOf(']', idx);
int nextEscape = v.indexOf('\\', idx);
int next = optMin(nextCloseBracket, nextEscape);
+
if (next == -1) {
// unexpected
return UNEXPECTED_TOKEN;
@@ -79,16 +92,19 @@ public final class ConfigSerializer {
idx = parseEscape(v, nextEscape, sb);
}
}
+
return idx;
}
private static int parseKeyValue(String v, int idx, ConfigStructureVisitor visitor) {
StringBuilder sb = new StringBuilder();
String k = null;
+
while (idx < v.length()) {
int nextEq = v.indexOf('=', idx);
int nextEscape = v.indexOf('\\', idx);
int next = optMin(nextEq, nextEscape);
+
if (next == -1) {
break;
} else if (next == nextEq) {
@@ -102,8 +118,10 @@ public final class ConfigSerializer {
idx = parseEscape(v, nextEscape, sb);
}
}
+
while (idx < v.length()) {
int nextEscape = v.indexOf('\\', idx);
+
if (nextEscape != -1) {
sb.append(v, idx, nextEscape);
idx = parseEscape(v, nextEscape, sb);
@@ -111,8 +129,13 @@ public final class ConfigSerializer {
break;
}
}
+
sb.append(v, idx, v.length());
- if (k == null) return NO_MATCH;
+
+ if (k == null) {
+ return NO_MATCH;
+ }
+
visitor.visitKeyValue(k, sb.toString());
return idx;
}
@@ -122,11 +145,14 @@ public final class ConfigSerializer {
if (v.charAt(idx + 1) == 'u') {
if (idx + 5 < v.length()) {
String codePoint = v.substring(idx + 2, idx + 6);
+
try {
int c = Integer.parseUnsignedInt(codePoint, 16);
sb.append((char) c);
} catch (NumberFormatException ignored) {
+ // ignored
}
+
idx = idx + 6;
}
} else if (v.charAt(idx + 1) == 'n') {
@@ -139,6 +165,7 @@ public final class ConfigSerializer {
} else {
idx = idx + 1;
}
+
return idx;
}
@@ -150,12 +177,17 @@ public final class ConfigSerializer {
private static void structureToString(ConfigSection section, StringBuilder sb, List pathStack) {
if (!section.values().isEmpty()) {
- if (sb.length() > 0) sb.append('\n');
+ if (sb.length() > 0) {
+ sb.append('\n');
+ }
+
pathStack.forEach(n -> sb.append('[').append(escapeSection(n)).append(']'));
- if (!pathStack.isEmpty()) sb.append('\n');
- section.values().entrySet().stream()
- .sorted(Entry.comparingByKey())
- .forEach(e -> sb.append(escapeKey(e.getKey())).append('=').append(escapeValue(e.getValue())).append('\n'));
+
+ if (!pathStack.isEmpty()) {
+ sb.append('\n');
+ }
+
+ section.values().entrySet().stream().sorted(Entry.comparingByKey()).forEach(e -> sb.append(escapeKey(e.getKey())).append('=').append(escapeValue(e.getValue())).append('\n'));
}
section.sections().entrySet().stream().sorted(Entry.comparingByKey()).forEach(e -> {
@@ -166,43 +198,37 @@ public final class ConfigSerializer {
}
private static String escapeSection(String s) {
- return s
- .replace("\\", "\\\\")
- .replace("\n", "\\n")
- .replace("]", "\\]")
- .chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
+ return s.replace("\\", "\\\\").replace("\n", "\\n").replace("]", "\\]").chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
}
private static String escapeKey(String s) {
- return s
- .replace("\\", "\\\\")
- .replace("[", "\\[")
- .replace("\n", "\\n")
- .replace("=", "\\=")
- .chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
+ return s.replace("\\", "\\\\").replace("[", "\\[").replace("\n", "\\n").replace("=", "\\=").chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
}
private static String escapeValue(String s) {
- return s
- .replace("\\", "\\\\")
- .replace("\n", "\\n")
- .chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
+ return s.replace("\\", "\\\\").replace("\n", "\\n").chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
}
public static Optional parseBool(String v) {
- if (v == null) return Optional.empty();
+ if (v == null) {
+ return Optional.empty();
+ }
+
switch (v) {
- case "true":
- return Optional.of(true);
- case "false":
- return Optional.of(false);
- default:
- return Optional.empty();
+ case "true":
+ return Optional.of(true);
+ case "false":
+ return Optional.of(false);
+ default:
+ return Optional.empty();
}
}
public static OptionalInt parseInt(String v) {
- if (v == null) return OptionalInt.empty();
+ if (v == null) {
+ return OptionalInt.empty();
+ }
+
try {
return OptionalInt.of(Integer.parseInt(v));
} catch (NumberFormatException e) {
@@ -211,7 +237,10 @@ public final class ConfigSerializer {
}
public static OptionalDouble parseDouble(String v) {
- if (v == null) return OptionalDouble.empty();
+ if (v == null) {
+ return OptionalDouble.empty();
+ }
+
try {
return OptionalDouble.of(Double.parseDouble(v));
} catch (NumberFormatException e) {
@@ -220,7 +249,10 @@ public final class ConfigSerializer {
}
public static OptionalInt parseRgbColor(String v) {
- if (v == null) return OptionalInt.empty();
+ if (v == null) {
+ return OptionalInt.empty();
+ }
+
try {
if (FULL_RGB_COLOR.matcher(v).matches()) {
return OptionalInt.of(Integer.parseUnsignedInt(v.substring(1), 16));
@@ -241,6 +273,7 @@ public final class ConfigSerializer {
public static String rgbColorToString(int color) {
color = color & 0xFFFFFF;
boolean isShort = ((color & 0xF0F0F0) >> 4 ^ color & 0x0F0F0F) == 0;
+
if (isShort) {
int packed = color & 0x0F0F0F;
packed = packed & 0xF | packed >> 4;
@@ -252,14 +285,19 @@ public final class ConfigSerializer {
}
public static Optional parseArray(String v) {
- if (v == null) return Optional.empty();
+ if (v == null) {
+ return Optional.empty();
+ }
+
List l = new ArrayList<>();
int idx = 0;
StringBuilder cur = new StringBuilder();
+
while (true) {
int nextSep = v.indexOf(',', idx);
int nextEsc = v.indexOf('\\', idx);
int next = optMin(nextSep, nextEsc);
+
if (next == -1) {
cur.append(v, idx, v.length());
l.add(cur.toString());
@@ -271,22 +309,25 @@ public final class ConfigSerializer {
idx = nextSep + 1;
} else if (next == nextEsc) {
cur.append(v, idx, nextEsc);
+
if (nextEsc + 1 < v.length()) {
cur.append(v.charAt(nextEsc + 1));
}
+
idx = nextEsc + 2;
}
}
}
public static String arrayToString(String[] values) {
- return Arrays.stream(values)
- .map(s -> s.replace("\\", "\\\\").replace(",", "\\,"))
- .collect(Collectors.joining(","));
+ return Arrays.stream(values).map(s -> s.replace("\\", "\\\\").replace(",", "\\,")).collect(Collectors.joining(","));
}
public static > Optional parseEnum(Function byName, String v) {
- if (v == null) return Optional.empty();
+ if (v == null) {
+ return Optional.empty();
+ }
+
try {
return Optional.of(byName.apply(v));
} catch (IllegalArgumentException e) {
@@ -295,9 +336,14 @@ public final class ConfigSerializer {
}
private static int optMin(int v1, int v2) {
- if (v1 == -1) return v2;
- if (v2 == -1) return v1;
+ if (v1 == -1) {
+ return v2;
+ }
+
+ if (v2 == -1) {
+ return v1;
+ }
+
return Math.min(v1, v2);
}
-
}
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java
index 12d7ec4..5374314 100644
--- a/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java
@@ -1,11 +1,9 @@
package cuchaz.enigma.config;
public interface ConfigStructureVisitor {
-
void visitKeyValue(String key, String value);
void visitSection(String section);
void jumpToRootSection();
-
}
diff --git a/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java b/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java
index 61fea4e..22be2e0 100644
--- a/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java
+++ b/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java
@@ -8,7 +8,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.utils.Result;
public interface ClassHandleListener {
-
default void onDeobfRefChanged(ClassHandle h, ClassEntry deobfRef) {
}
@@ -32,5 +31,4 @@ public interface ClassHandleListener {
JAVADOC,
MAPPINGS,
}
-
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java b/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java
index 5f371a5..9475d74 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java
@@ -1,6 +1,10 @@
package cuchaz.enigma.source;
-import java.util.*;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
import javax.annotation.Nullable;
@@ -62,6 +66,7 @@ public class DecompiledClassSource {
return translatedEntry.getValue().getSourceRemapName();
} else {
Optional proposedName = proposeName(project, entry);
+
if (proposedName.isPresent()) {
target.add(RenamableTokenType.PROPOSED, movedToken);
return proposedName.get();
@@ -72,6 +77,7 @@ public class DecompiledClassSource {
}
String defaultName = generateDefaultName(translatedEntry.getValue());
+
if (defaultName != null) {
return defaultName;
}
@@ -86,10 +92,7 @@ public class DecompiledClassSource {
EntryRemapper mapper = project.getMapper();
Collection> resolved = mapper.getObfResolver().resolveEntry(entry, ResolutionStrategy.RESOLVE_ROOT);
- return resolved.stream()
- .map(e -> nameProposalService.proposeName(e, mapper))
- .filter(Optional::isPresent)
- .map(Optional::get);
+ return resolved.stream().map(e -> nameProposalService.proposeName(e, mapper)).filter(Optional::isPresent).map(Optional::get);
}).findFirst();
}
@@ -99,6 +102,7 @@ public class DecompiledClassSource {
LocalVariableDefEntry localVariable = (LocalVariableDefEntry) entry;
int index = localVariable.getIndex();
+
if (localVariable.isArgument()) {
List arguments = localVariable.getParent().getDesc().getArgumentDescs();
return LocalNameGenerator.generateArgumentName(index, localVariable.getDesc(), arguments);
@@ -139,9 +143,11 @@ public class DecompiledClassSource {
Iterator fromTokenItr = fromIndex.referenceTokens().iterator();
Iterator toTokenItr = toIndex.referenceTokens().iterator();
+
while (fromTokenItr.hasNext() && toTokenItr.hasNext()) {
Token fromToken = fromTokenItr.next();
Token toToken = toTokenItr.next();
+
if (fromToken.end > fromOffset) {
break;
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java b/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java
index 938a736..b31dcc4 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java
@@ -1,8 +1,9 @@
package cuchaz.enigma.source;
-import cuchaz.enigma.translation.mapping.EntryRemapper;
import org.checkerframework.checker.nullness.qual.Nullable;
+import cuchaz.enigma.translation.mapping.EntryRemapper;
+
public interface Decompiler {
@Deprecated // use remapper specific one for easy doc inclusion
default Source getSource(String className) {
diff --git a/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java b/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java
index 638498f..a87fc98 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java
@@ -1,11 +1,11 @@
package cuchaz.enigma.source;
-import cuchaz.enigma.classprovider.ClassProvider;
import cuchaz.enigma.api.service.EnigmaService;
import cuchaz.enigma.api.service.EnigmaServiceType;
+import cuchaz.enigma.classprovider.ClassProvider;
public interface DecompilerService extends EnigmaService {
- EnigmaServiceType TYPE = EnigmaServiceType.create("decompiler");
+ EnigmaServiceType TYPE = EnigmaServiceType.create("decompiler");
- Decompiler create(ClassProvider classProvider, SourceSettings settings);
+ Decompiler create(ClassProvider classProvider, SourceSettings settings);
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java b/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java
index 643ea7a..0e3244d 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java
@@ -5,7 +5,7 @@ import cuchaz.enigma.source.cfr.CfrDecompiler;
import cuchaz.enigma.source.procyon.ProcyonDecompiler;
public class Decompilers {
- public static final DecompilerService PROCYON = ProcyonDecompiler::new;
- public static final DecompilerService CFR = CfrDecompiler::new;
- public static final DecompilerService BYTECODE = BytecodeDecompiler::new;
+ public static final DecompilerService PROCYON = ProcyonDecompiler::new;
+ public static final DecompilerService CFR = CfrDecompiler::new;
+ public static final DecompilerService BYTECODE = BytecodeDecompiler::new;
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Source.java b/enigma/src/main/java/cuchaz/enigma/source/Source.java
index 6ecce7c..fe45805 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/Source.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/Source.java
@@ -3,9 +3,9 @@ package cuchaz.enigma.source;
import cuchaz.enigma.translation.mapping.EntryRemapper;
public interface Source {
- String asString();
+ String asString();
- Source withJavadocs(EntryRemapper remapper);
+ Source withJavadocs(EntryRemapper remapper);
- SourceIndex index();
+ SourceIndex index();
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java b/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java
index 971252e..e9d928e 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java
@@ -1,172 +1,170 @@
package cuchaz.enigma.source;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
+
import cuchaz.enigma.analysis.EntryReference;
import cuchaz.enigma.translation.mapping.EntryResolver;
import cuchaz.enigma.translation.mapping.ResolutionStrategy;
import cuchaz.enigma.translation.representation.entry.Entry;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
public class SourceIndex {
- private String source;
- private List lineOffsets;
- private final TreeMap, Entry>>> tokenToReference;
- private final Multimap, Entry>>, Token> referenceToTokens;
- private final Map, Token> declarationToToken;
-
- public SourceIndex() {
- tokenToReference = new TreeMap<>();
- referenceToTokens = HashMultimap.create();
- declarationToToken = Maps.newHashMap();
- }
-
- public SourceIndex(String source) {
- this();
- setSource(source);
- }
-
- public void setSource(String source) {
- this.source = source;
- lineOffsets = Lists.newArrayList();
- lineOffsets.add(0);
-
- for (int i = 0; i < this.source.length(); i++) {
- if (this.source.charAt(i) == '\n') {
- lineOffsets.add(i + 1);
- }
- }
- }
-
- public String getSource() {
- return source;
- }
-
- public int getLineNumber(int position) {
- int line = 0;
-
- for (int offset : lineOffsets) {
- if (offset > position) {
- break;
- }
-
- line++;
- }
-
- return line;
- }
-
- public int getColumnNumber(int position) {
- return position - lineOffsets.get(getLineNumber(position) - 1) + 1;
- }
-
- public int getPosition(int line, int column) {
- return lineOffsets.get(line - 1) + column - 1;
- }
-
- public Iterable> declarations() {
- return declarationToToken.keySet();
- }
-
- public Iterable declarationTokens() {
- return declarationToToken.values();
- }
-
- public Token getDeclarationToken(Entry> entry) {
- return declarationToToken.get(entry);
- }
-
- public void addDeclaration(Token token, Entry> deobfEntry) {
- if (token != null) {
- EntryReference, Entry>> reference = new EntryReference<>(deobfEntry, token.text);
- tokenToReference.put(token, reference);
- referenceToTokens.put(reference, token);
- referenceToTokens.put(EntryReference.declaration(deobfEntry, token.text), token);
- declarationToToken.put(deobfEntry, token);
- }
- }
-
- public Iterable, Entry>>> references() {
- return referenceToTokens.keySet();
- }
-
- public EntryReference, Entry>> getReference(Token token) {
- if (token == null) {
- return null;
- }
-
- return tokenToReference.get(token);
- }
-
- public Iterable referenceTokens() {
- return tokenToReference.keySet();
- }
-
- public Token getReferenceToken(int pos) {
- Token token = tokenToReference.floorKey(new Token(pos, pos, null));
-
- if (token != null && token.contains(pos)) {
- return token;
- }
-
- return null;
- }
-
- public Collection getReferenceTokens(EntryReference, Entry>> deobfReference) {
- return referenceToTokens.get(deobfReference);
- }
-
- public void addReference(Token token, Entry> deobfEntry, Entry> deobfContext) {
- if (token != null) {
- EntryReference, Entry>> deobfReference = new EntryReference<>(deobfEntry, token.text, deobfContext);
- tokenToReference.put(token, deobfReference);
- referenceToTokens.put(deobfReference, token);
- }
- }
-
- public void resolveReferences(EntryResolver resolver) {
- // resolve all the classes in the source references
- for (Token token : Lists.newArrayList(referenceToTokens.values())) {
- EntryReference, Entry>> reference = tokenToReference.get(token);
- EntryReference, Entry>> resolvedReference = resolver.resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST);
-
- // replace the reference
- tokenToReference.replace(token, resolvedReference);
-
- Collection tokens = referenceToTokens.removeAll(reference);
- referenceToTokens.putAll(resolvedReference, tokens);
- }
- }
-
- public SourceIndex remapTo(SourceRemapper.Result result) {
- SourceIndex remapped = new SourceIndex(result.getSource());
-
- for (Map.Entry, Token> entry : declarationToToken.entrySet()) {
- remapped.declarationToToken.put(entry.getKey(), result.getRemappedToken(entry.getValue()));
- }
-
- for (Map.Entry, Entry>>, Collection> entry : referenceToTokens.asMap().entrySet()) {
- EntryReference, Entry>> reference = entry.getKey();
- Collection oldTokens = entry.getValue();
-
- Collection newTokens = oldTokens
- .stream()
- .map(result::getRemappedToken)
- .toList();
-
- remapped.referenceToTokens.putAll(reference, newTokens);
- }
-
- for (Map.Entry, Entry>>> entry : tokenToReference.entrySet()) {
- remapped.tokenToReference.put(result.getRemappedToken(entry.getKey()), entry.getValue());
- }
-
- return remapped;
- }
+ private String source;
+ private List lineOffsets;
+ private final TreeMap, Entry>>> tokenToReference;
+ private final Multimap, Entry>>, Token> referenceToTokens;
+ private final Map, Token> declarationToToken;
+
+ public SourceIndex() {
+ tokenToReference = new TreeMap<>();
+ referenceToTokens = HashMultimap.create();
+ declarationToToken = Maps.newHashMap();
+ }
+
+ public SourceIndex(String source) {
+ this();
+ setSource(source);
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ lineOffsets = Lists.newArrayList();
+ lineOffsets.add(0);
+
+ for (int i = 0; i < this.source.length(); i++) {
+ if (this.source.charAt(i) == '\n') {
+ lineOffsets.add(i + 1);
+ }
+ }
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public int getLineNumber(int position) {
+ int line = 0;
+
+ for (int offset : lineOffsets) {
+ if (offset > position) {
+ break;
+ }
+
+ line++;
+ }
+
+ return line;
+ }
+
+ public int getColumnNumber(int position) {
+ return position - lineOffsets.get(getLineNumber(position) - 1) + 1;
+ }
+
+ public int getPosition(int line, int column) {
+ return lineOffsets.get(line - 1) + column - 1;
+ }
+
+ public Iterable> declarations() {
+ return declarationToToken.keySet();
+ }
+
+ public Iterable declarationTokens() {
+ return declarationToToken.values();
+ }
+
+ public Token getDeclarationToken(Entry> entry) {
+ return declarationToToken.get(entry);
+ }
+
+ public void addDeclaration(Token token, Entry> deobfEntry) {
+ if (token != null) {
+ EntryReference, Entry>> reference = new EntryReference<>(deobfEntry, token.text);
+ tokenToReference.put(token, reference);
+ referenceToTokens.put(reference, token);
+ referenceToTokens.put(EntryReference.declaration(deobfEntry, token.text), token);
+ declarationToToken.put(deobfEntry, token);
+ }
+ }
+
+ public Iterable, Entry>>> references() {
+ return referenceToTokens.keySet();
+ }
+
+ public EntryReference, Entry>> getReference(Token token) {
+ if (token == null) {
+ return null;
+ }
+
+ return tokenToReference.get(token);
+ }
+
+ public Iterable referenceTokens() {
+ return tokenToReference.keySet();
+ }
+
+ public Token getReferenceToken(int pos) {
+ Token token = tokenToReference.floorKey(new Token(pos, pos, null));
+
+ if (token != null && token.contains(pos)) {
+ return token;
+ }
+
+ return null;
+ }
+
+ public Collection getReferenceTokens(EntryReference, Entry>> deobfReference) {
+ return referenceToTokens.get(deobfReference);
+ }
+
+ public void addReference(Token token, Entry> deobfEntry, Entry> deobfContext) {
+ if (token != null) {
+ EntryReference, Entry>> deobfReference = new EntryReference<>(deobfEntry, token.text, deobfContext);
+ tokenToReference.put(token, deobfReference);
+ referenceToTokens.put(deobfReference, token);
+ }
+ }
+
+ public void resolveReferences(EntryResolver resolver) {
+ // resolve all the classes in the source references
+ for (Token token : Lists.newArrayList(referenceToTokens.values())) {
+ EntryReference, Entry>> reference = tokenToReference.get(token);
+ EntryReference, Entry>> resolvedReference = resolver.resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST);
+
+ // replace the reference
+ tokenToReference.replace(token, resolvedReference);
+
+ Collection tokens = referenceToTokens.removeAll(reference);
+ referenceToTokens.putAll(resolvedReference, tokens);
+ }
+ }
+
+ public SourceIndex remapTo(SourceRemapper.Result result) {
+ SourceIndex remapped = new SourceIndex(result.getSource());
+
+ for (Map.Entry, Token> entry : declarationToToken.entrySet()) {
+ remapped.declarationToToken.put(entry.getKey(), result.getRemappedToken(entry.getValue()));
+ }
+
+ for (Map.Entry, Entry>>, Collection> entry : referenceToTokens.asMap().entrySet()) {
+ EntryReference, Entry>> reference = entry.getKey();
+ Collection oldTokens = entry.getValue();
+
+ Collection newTokens = oldTokens.stream().map(result::getRemappedToken).toList();
+
+ remapped.referenceToTokens.putAll(reference, newTokens);
+ }
+
+ for (Map.Entry, Entry>>> entry : tokenToReference.entrySet()) {
+ remapped.tokenToReference.put(result.getRemappedToken(entry.getKey()), entry.getValue());
+ }
+
+ return remapped;
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java b/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java
index b5f8006..f12c387 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java
@@ -17,10 +17,12 @@ public class SourceRemapper {
Map remappedTokens = new HashMap<>();
int accumulatedOffset = 0;
+
for (Token token : tokens) {
Token movedToken = token.move(accumulatedOffset);
String remappedName = remapper.remap(token, movedToken);
+
if (remappedName != null) {
accumulatedOffset += movedToken.getRenameOffset(remappedName);
movedToken.rename(remappedSource, remappedName);
diff --git a/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java b/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java
index f6c68e9..1754770 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java
@@ -1,11 +1,11 @@
package cuchaz.enigma.source;
public class SourceSettings {
- public final boolean removeImports;
- public final boolean removeVariableFinal;
+ public final boolean removeImports;
+ public final boolean removeVariableFinal;
- public SourceSettings(boolean removeImports, boolean removeVariableFinal) {
- this.removeImports = removeImports;
- this.removeVariableFinal = removeVariableFinal;
- }
+ public SourceSettings(boolean removeImports, boolean removeVariableFinal) {
+ this.removeImports = removeImports;
+ this.removeVariableFinal = removeVariableFinal;
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Token.java b/enigma/src/main/java/cuchaz/enigma/source/Token.java
index 7d729ab..5c14234 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/Token.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/Token.java
@@ -1,18 +1,17 @@
/*******************************************************************************
- * 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
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
+* 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
+*
+*
Contributors:
+* Jeff Martin - initial API and implementation
+******************************************************************************/
package cuchaz.enigma.source;
public class Token implements Comparable {
-
public int start;
public int end;
public String text;
diff --git a/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java b/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java
index f32d918..179eece 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java
@@ -1,9 +1,14 @@
package cuchaz.enigma.source;
-import java.util.*;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.TreeSet;
public final class TokenStore {
-
private static final TokenStore EMPTY = new TokenStore(Collections.emptyNavigableSet(), Collections.emptyMap(), null);
private final NavigableSet tokens;
@@ -18,9 +23,11 @@ public final class TokenStore {
public static TokenStore create(SourceIndex obfuscatedIndex) {
EnumMap> map = new EnumMap<>(RenamableTokenType.class);
+
for (RenamableTokenType value : RenamableTokenType.values()) {
map.put(value, new TreeSet<>(Comparator.comparing(t -> t.start)));
}
+
return new TokenStore(new TreeSet<>(Comparator.comparing(t -> t.start)), Collections.unmodifiableMap(map), obfuscatedIndex.getSource());
}
@@ -34,22 +41,25 @@ public final class TokenStore {
}
public boolean isCompatible(TokenStore other) {
- return this.obfSource != null && other.obfSource != null &&
- this.obfSource.equals(other.obfSource) &&
- this.tokens.size() == other.tokens.size();
+ return this.obfSource != null && other.obfSource != null && this.obfSource.equals(other.obfSource) && this.tokens.size() == other.tokens.size();
}
public int mapPosition(TokenStore to, int position) {
- if (!this.isCompatible(to)) return 0;
+ if (!this.isCompatible(to)) {
+ return 0;
+ }
int newPos = position;
Iterator thisIter = this.tokens.iterator();
Iterator toIter = to.tokens.iterator();
+
while (thisIter.hasNext()) {
Token token = thisIter.next();
Token newToken = toIter.next();
- if (position < token.start) break;
+ if (position < token.start) {
+ break;
+ }
// if we're inside the token and the text changed,
// snap the cursor to the beginning
@@ -67,5 +77,4 @@ public final class TokenStore {
public Map> getByType() {
return byType;
}
-
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java
index 97d2969..6461d20 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java
@@ -1,21 +1,22 @@
package cuchaz.enigma.source.bytecode;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
import cuchaz.enigma.classprovider.ClassProvider;
import cuchaz.enigma.source.Decompiler;
import cuchaz.enigma.source.Source;
import cuchaz.enigma.source.SourceSettings;
import cuchaz.enigma.translation.mapping.EntryRemapper;
-import org.checkerframework.checker.nullness.qual.Nullable;
public class BytecodeDecompiler implements Decompiler {
- private final ClassProvider classProvider;
+ private final ClassProvider classProvider;
- public BytecodeDecompiler(ClassProvider classProvider, SourceSettings settings) {
- this.classProvider = classProvider;
- }
+ public BytecodeDecompiler(ClassProvider classProvider, SourceSettings settings) {
+ this.classProvider = classProvider;
+ }
- @Override
- public Source getSource(String className, @Nullable EntryRemapper remapper) {
- return new BytecodeSource(classProvider.get(className), remapper);
- }
+ @Override
+ public Source getSource(String className, @Nullable EntryRemapper remapper) {
+ return new BytecodeSource(classProvider.get(className), remapper);
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java
index 4364b40..bcb5455 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java
@@ -1,56 +1,57 @@
package cuchaz.enigma.source.bytecode;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.util.TraceClassVisitor;
+
import cuchaz.enigma.Enigma;
import cuchaz.enigma.bytecode.translators.TranslationClassVisitor;
import cuchaz.enigma.source.Source;
import cuchaz.enigma.source.SourceIndex;
import cuchaz.enigma.translation.mapping.EntryRemapper;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.util.TraceClassVisitor;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
public class BytecodeSource implements Source {
- private final ClassNode classNode;
- private final EntryRemapper remapper;
+ private final ClassNode classNode;
+ private final EntryRemapper remapper;
- public BytecodeSource(ClassNode classNode, EntryRemapper remapper) {
- this.classNode = classNode;
- this.remapper = remapper;
- }
+ public BytecodeSource(ClassNode classNode, EntryRemapper remapper) {
+ this.classNode = classNode;
+ this.remapper = remapper;
+ }
- @Override
- public String asString() {
- return index().getSource();
- }
+ @Override
+ public String asString() {
+ return index().getSource();
+ }
- @Override
- public Source withJavadocs(EntryRemapper remapper) {
- return new BytecodeSource(classNode, remapper);
- }
+ @Override
+ public Source withJavadocs(EntryRemapper remapper) {
+ return new BytecodeSource(classNode, remapper);
+ }
- @Override
- public SourceIndex index() {
- SourceIndex index = new SourceIndex();
+ @Override
+ public SourceIndex index() {
+ SourceIndex index = new SourceIndex();
- EnigmaTextifier textifier = new EnigmaTextifier(index);
- StringWriter out = new StringWriter();
- PrintWriter writer = new PrintWriter(out);
+ EnigmaTextifier textifier = new EnigmaTextifier(index);
+ StringWriter out = new StringWriter();
+ PrintWriter writer = new PrintWriter(out);
- TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, textifier, writer);
+ TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, textifier, writer);
- ClassNode node = this.classNode;
+ ClassNode node = this.classNode;
- if (remapper != null) {
- ClassNode translatedNode = new ClassNode();
- node.accept(new TranslationClassVisitor(remapper.getDeobfuscator(), Enigma.ASM_VERSION, translatedNode));
- node = translatedNode;
- }
+ if (remapper != null) {
+ ClassNode translatedNode = new ClassNode();
+ node.accept(new TranslationClassVisitor(remapper.getDeobfuscator(), Enigma.ASM_VERSION, translatedNode));
+ node = translatedNode;
+ }
- node.accept(traceClassVisitor);
- index.setSource(out.toString());
+ node.accept(traceClassVisitor);
+ index.setSource(out.toString());
- return index;
- }
+ return index;
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java b/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java
index 2f3fcf2..f1586ee 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java
@@ -1,14 +1,15 @@
package cuchaz.enigma.source.bytecode;
+import org.objectweb.asm.util.Textifier;
+
import cuchaz.enigma.Enigma;
import cuchaz.enigma.source.SourceIndex;
-import org.objectweb.asm.util.Textifier;
public class EnigmaTextifier extends Textifier {
- private final SourceIndex sourceIndex;
+ private final SourceIndex sourceIndex;
- public EnigmaTextifier(SourceIndex sourceIndex) {
- super(Enigma.ASM_VERSION);
- this.sourceIndex = sourceIndex;
- }
+ public EnigmaTextifier(SourceIndex sourceIndex) {
+ super(Enigma.ASM_VERSION);
+ this.sourceIndex = sourceIndex;
+ }
}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
index cd7b2aa..5531236 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
@@ -1,11 +1,8 @@
package cuchaz.enigma.source.cfr;
-import cuchaz.enigma.classprovider.ClassProvider;
-import cuchaz.enigma.source.Decompiler;
-import cuchaz.enigma.source.Source;
-import cuchaz.enigma.source.SourceSettings;
-import cuchaz.enigma.translation.mapping.EntryRemapper;
-import cuchaz.enigma.utils.AsmUtil;
+import java.util.Collection;
+import java.util.Map;
+
import org.benf.cfr.reader.apiunreleased.ClassFileSource2;
import org.benf.cfr.reader.apiunreleased.JarContent;
import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;
@@ -15,55 +12,59 @@ import org.benf.cfr.reader.util.getopt.OptionsImpl;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.objectweb.asm.tree.ClassNode;
-import java.util.Collection;
-import java.util.Map;
+import cuchaz.enigma.classprovider.ClassProvider;
+import cuchaz.enigma.source.Decompiler;
+import cuchaz.enigma.source.Source;
+import cuchaz.enigma.source.SourceSettings;
+import cuchaz.enigma.translation.mapping.EntryRemapper;
+import cuchaz.enigma.utils.AsmUtil;
public class CfrDecompiler implements Decompiler {
- // cfr doesn't add final on params so final setting is ignored
- private final SourceSettings settings;
- private final Options options;
- private final ClassFileSource2 classFileSource;
+ // cfr doesn't add final on params so final setting is ignored
+ private final SourceSettings settings;
+ private final Options options;
+ private final ClassFileSource2 classFileSource;
- public CfrDecompiler(ClassProvider classProvider, SourceSettings sourceSettings) {
- this.options = OptionsImpl.getFactory().create( Map.of("trackbytecodeloc", "true"));
- this.settings = sourceSettings;
- this.classFileSource = new ClassFileSource(classProvider);
- }
+ public CfrDecompiler(ClassProvider classProvider, SourceSettings sourceSettings) {
+ this.options = OptionsImpl.getFactory().create(Map.of("trackbytecodeloc", "true"));
+ this.settings = sourceSettings;
+ this.classFileSource = new ClassFileSource(classProvider);
+ }
- @Override
- public Source getSource(String className, @Nullable EntryRemapper mapper) {
- return new CfrSource(className, settings, this.options, this.classFileSource, mapper);
- }
+ @Override
+ public Source getSource(String className, @Nullable EntryRemapper mapper) {
+ return new CfrSource(className, settings, this.options, this.classFileSource, mapper);
+ }
- private record ClassFileSource(ClassProvider classProvider) implements ClassFileSource2 {
- @Override
- public JarContent addJarContent(String s, AnalysisType analysisType) {
- return null;
- }
+ private record ClassFileSource(ClassProvider classProvider) implements ClassFileSource2 {
+ @Override
+ public JarContent addJarContent(String s, AnalysisType analysisType) {
+ return null;
+ }
- @Override
- public void informAnalysisRelativePathDetail(String usePath, String classFilePath) {
- }
+ @Override
+ public void informAnalysisRelativePathDetail(String usePath, String classFilePath) {
+ }
- @Override
- public Collection addJar(String jarPath) {
- return null;
- }
+ @Override
+ public Collection addJar(String jarPath) {
+ return null;
+ }
- @Override
- public String getPossiblyRenamedPath(String path) {
- return path;
- }
+ @Override
+ public String getPossiblyRenamedPath(String path) {
+ return path;
+ }
- @Override
- public Pair getClassFileContent(String path) {
- ClassNode node = classProvider.get(path.substring(0, path.lastIndexOf('.')));
+ @Override
+ public Pair