From 0f47403d0220757fed189b76e2071e25b1025cb8 Mon Sep 17 00:00:00 2001 From: Runemoro Date: Wed, 3 Jun 2020 13:39:42 -0400 Subject: Split GUI code to separate module (#242) * Split into modules * Post merge compile fixes Co-authored-by: modmuss50 --- src/main/java/cuchaz/enigma/analysis/Access.java | 43 ----- .../java/cuchaz/enigma/analysis/BuiltinPlugin.java | 157 ------------------ .../java/cuchaz/enigma/analysis/ClassCache.java | 127 --------------- .../analysis/ClassImplementationsTreeNode.java | 72 --------- .../enigma/analysis/ClassInheritanceTreeNode.java | 72 --------- .../enigma/analysis/ClassReferenceTreeNode.java | 94 ----------- .../cuchaz/enigma/analysis/EntryReference.java | 140 ---------------- .../enigma/analysis/FieldReferenceTreeNode.java | 83 ---------- .../enigma/analysis/IndexSimpleVerifier.java | 154 ------------------ .../cuchaz/enigma/analysis/IndexTreeBuilder.java | 74 --------- .../cuchaz/enigma/analysis/InterpreterPair.java | 131 --------------- .../analysis/MethodImplementationsTreeNode.java | 85 ---------- .../enigma/analysis/MethodInheritanceTreeNode.java | 95 ----------- .../enigma/analysis/MethodNodeWithAction.java | 19 --- .../enigma/analysis/MethodReferenceTreeNode.java | 113 ------------- .../enigma/analysis/ReferenceTargetType.java | 74 --------- .../cuchaz/enigma/analysis/ReferenceTreeNode.java | 20 --- src/main/java/cuchaz/enigma/analysis/Token.java | 72 --------- .../enigma/analysis/index/BridgeMethodIndex.java | 156 ------------------ .../cuchaz/enigma/analysis/index/EntryIndex.java | 102 ------------ .../enigma/analysis/index/IndexClassVisitor.java | 40 ----- .../analysis/index/IndexReferenceVisitor.java | 180 --------------------- .../enigma/analysis/index/InheritanceIndex.java | 127 --------------- .../cuchaz/enigma/analysis/index/JarIndex.java | 171 -------------------- .../cuchaz/enigma/analysis/index/JarIndexer.java | 28 ---- .../analysis/index/PackageVisibilityIndex.java | 147 ----------------- .../enigma/analysis/index/ReferenceIndex.java | 148 ----------------- 27 files changed, 2724 deletions(-) delete mode 100644 src/main/java/cuchaz/enigma/analysis/Access.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/ClassCache.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/EntryReference.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/InterpreterPair.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/Token.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/JarIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java (limited to 'src/main/java/cuchaz/enigma/analysis') diff --git a/src/main/java/cuchaz/enigma/analysis/Access.java b/src/main/java/cuchaz/enigma/analysis/Access.java deleted file mode 100644 index 82ca669..0000000 --- a/src/main/java/cuchaz/enigma/analysis/Access.java +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* - * 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 { - - PUBLIC, PROTECTED, PACKAGE, PRIVATE; - - public static Access get(AccessFlags flags) { - return get(flags.getFlags()); - } - - public static Access get(int modifiers) { - boolean isPublic = Modifier.isPublic(modifiers); - boolean isProtected = Modifier.isProtected(modifiers); - boolean isPrivate = Modifier.isPrivate(modifiers); - - if (isPublic && !isProtected && !isPrivate) { - return PUBLIC; - } else if (!isPublic && isProtected && !isPrivate) { - return PROTECTED; - } else if (!isPublic && !isProtected && isPrivate) { - return PRIVATE; - } else if (!isPublic && !isProtected && !isPrivate) { - return PACKAGE; - } - // assume public by default - return PUBLIC; - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java b/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java deleted file mode 100644 index dc3f553..0000000 --- a/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java +++ /dev/null @@ -1,157 +0,0 @@ -package cuchaz.enigma.analysis; - -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.source.procyon.ProcyonDecompiler; -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 cuchaz.enigma.utils.Utils; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.analysis.Analyzer; -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; - -public final class BuiltinPlugin implements EnigmaPlugin { - - public BuiltinPlugin() { - } - - @Override - public void init(EnigmaPluginContext ctx) { - registerEnumNamingService(ctx); - registerDecompilerServices(ctx); - } - - private void registerEnumNamingService(EnigmaPluginContext ctx) { - final Map, String> names = new HashMap<>(); - final EnumFieldNameFindingVisitor visitor = new EnumFieldNameFindingVisitor(names); - - ctx.registerService("enigma:enum_initializer_indexer", JarIndexerService.TYPE, ctx1 -> (classCache, jarIndex) -> classCache.visit(() -> visitor, ClassReader.SKIP_FRAMES)); - ctx.registerService("enigma:enum_name_proposer", NameProposalService.TYPE, ctx1 -> (obfEntry, remapper) -> Optional.ofNullable(names.get(obfEntry))); - } - - private void registerDecompilerServices(EnigmaPluginContext ctx) { - ctx.registerService("enigma:procyon", DecompilerService.TYPE, ctx1 -> Decompilers.PROCYON); - ctx.registerService("enigma:cfr", DecompilerService.TYPE, ctx1 -> Decompilers.CFR); - } - - private static final class EnumFieldNameFindingVisitor extends ClassVisitor { - - private ClassEntry clazz; - private String className; - private final Map, String> mappings; - private final Set> enumFields = new HashSet<>(); - private final List classInits = new ArrayList<>(); - - EnumFieldNameFindingVisitor(Map, String> mappings) { - super(Utils.ASM_VERSION); - this.mappings = mappings; - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - super.visit(version, access, name, signature, superName, interfaces); - this.className = name; - this.clazz = new ClassEntry(name); - this.enumFields.clear(); - this.classInits.clear(); - } - - @Override - public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { - if ((access & Opcodes.ACC_ENUM) != 0) { - if (!enumFields.add(new Pair<>(name, descriptor))) { - throw new IllegalArgumentException("Found two enum fields with the same name \"" + name + "\" and desc \"" + descriptor + "\"!"); - } - } - return super.visitField(access, name, descriptor, signature, value); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - if ("".equals(name)) { - MethodNode node = new MethodNode(api, access, name, descriptor, signature, exceptions); - classInits.add(node); - return node; - } - return super.visitMethod(access, name, descriptor, signature, exceptions); - } - - @Override - public void visitEnd() { - super.visitEnd(); - try { - collectResults(); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - private void collectResults() throws Exception { - String owner = className; - Analyzer analyzer = new Analyzer<>(new SourceInterpreter()); - - 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)) { - - 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)) { - if (s == null) { - s = (String) (((LdcInsnNode) ci).cst); - // stringsFound++; - } - } - } - } - } - - if (s != null) { - mappings.put(new FieldEntry(clazz, ((FieldInsnNode) instr2).name, new TypeDescriptor(((FieldInsnNode) instr2).desc)), s); - } - // report otherwise? - } - } - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/ClassCache.java b/src/main/java/cuchaz/enigma/analysis/ClassCache.java deleted file mode 100644 index f694bf3..0000000 --- a/src/main/java/cuchaz/enigma/analysis/ClassCache.java +++ /dev/null @@ -1,127 +0,0 @@ -package cuchaz.enigma.analysis; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.collect.ImmutableSet; -import cuchaz.enigma.ClassProvider; -import cuchaz.enigma.ProgressListener; -import cuchaz.enigma.analysis.index.JarIndex; -import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor; -import cuchaz.enigma.utils.Utils; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.ClassNode; - -import javax.annotation.Nullable; -import java.io.IOException; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; - -public final class ClassCache implements AutoCloseable, ClassProvider { - private final FileSystem fileSystem; - private final ImmutableSet classNames; - - private final Cache nodeCache = CacheBuilder.newBuilder() - .maximumSize(128) - .expireAfterAccess(1, TimeUnit.MINUTES) - .build(); - - private ClassCache(FileSystem fileSystem, ImmutableSet classNames) { - this.fileSystem = fileSystem; - this.classNames = classNames; - } - - public static ClassCache of(Path jarPath) throws IOException { - FileSystem fileSystem = FileSystems.newFileSystem(jarPath, (ClassLoader) null); - ImmutableSet classNames = collectClassNames(fileSystem); - - return new ClassCache(fileSystem, classNames); - } - - 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); - } - }); - } - - return classNames.build(); - } - - @Nullable - @Override - public ClassNode getClassNode(String name) { - if (!classNames.contains(name)) { - return null; - } - - try { - return nodeCache.get(name, () -> parseNode(name)); - } catch (ExecutionException e) { - throw new RuntimeException(e); - } - } - - private ClassNode parseNode(String name) throws IOException { - ClassReader reader = getReader(name); - - ClassNode node = new ClassNode(); - - LocalVariableFixVisitor visitor = new LocalVariableFixVisitor(Utils.ASM_VERSION, node); - reader.accept(visitor, 0); - - return node; - } - - private ClassReader getReader(String name) throws IOException { - Path path = fileSystem.getPath(name + ".class"); - byte[] bytes = Files.readAllBytes(path); - return new ClassReader(bytes); - } - - public int getClassCount() { - return classNames.size(); - } - - public void visit(Supplier visitorSupplier, int readFlags) { - for (String className : classNames) { - ClassVisitor visitor = visitorSupplier.get(); - - ClassNode cached = nodeCache.getIfPresent(className); - if (cached != null) { - cached.accept(visitor); - continue; - } - - try { - ClassReader reader = getReader(className); - reader.accept(visitor, readFlags); - } catch (IOException e) { - System.out.println("Failed to visit class " + className); - e.printStackTrace(); - } - } - } - - @Override - public void close() throws IOException { - this.fileSystem.close(); - } - - public JarIndex index(ProgressListener progress) { - JarIndex index = JarIndex.empty(); - index.indexJar(this, progress); - return index; - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java deleted file mode 100644 index 0fc44ca..0000000 --- a/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * 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 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; - - public ClassImplementationsTreeNode(Translator translator, ClassEntry entry) { - this.translator = translator; - this.entry = entry; - } - - public static ClassImplementationsTreeNode findNode(ClassImplementationsTreeNode node, MethodEntry entry) { - // is this the node? - if (node.entry.equals(entry.getParent())) { - return node; - } - - // recurse - for (int i = 0; i < node.getChildCount(); i++) { - ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode) node.getChildAt(i), entry); - if (foundNode != null) { - return foundNode; - } - } - return null; - } - - public ClassEntry getClassEntry() { - return this.entry; - } - - @Override - public String toString() { - return translator.translate(entry).toString(); - } - - public void load(JarIndex index) { - // get all method implementations - List nodes = Lists.newArrayList(); - InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); - - Collection inheritors = inheritanceIndex.getChildren(entry); - for (ClassEntry inheritor : inheritors) { - nodes.add(new ClassImplementationsTreeNode(translator, inheritor)); - } - - // add them to this node - nodes.forEach(this::add); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java deleted file mode 100644 index 7904c5f..0000000 --- a/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * 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 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; - - public ClassInheritanceTreeNode(Translator translator, String obfClassName) { - this.translator = translator; - this.obfClassEntry = new ClassEntry(obfClassName); - } - - public static ClassInheritanceTreeNode findNode(ClassInheritanceTreeNode node, ClassEntry entry) { - // is this the node? - if (node.getObfClassName().equals(entry.getFullName())) { - return node; - } - - // recurse - for (int i = 0; i < node.getChildCount(); i++) { - ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode) node.getChildAt(i), entry); - if (foundNode != null) { - return foundNode; - } - } - return null; - } - - public String getObfClassName() { - return this.obfClassEntry.getFullName(); - } - - @Override - public String toString() { - return translator.translate(obfClassEntry).getFullName(); - } - - 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())); - } - - // add them to this node - nodes.forEach(this::add); - - if (recurse) { - for (ClassInheritanceTreeNode node : nodes) { - node.load(ancestries, true); - } - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java deleted file mode 100644 index 90d8a6c..0000000 --- a/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - * 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 com.google.common.collect.Sets; -import cuchaz.enigma.analysis.index.JarIndex; -import cuchaz.enigma.analysis.index.ReferenceIndex; -import cuchaz.enigma.translation.Translator; -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 { - - private Translator deobfuscatingTranslator; - private ClassEntry entry; - private EntryReference reference; - - public ClassReferenceTreeNode(Translator deobfuscatingTranslator, ClassEntry entry) { - this.deobfuscatingTranslator = deobfuscatingTranslator; - this.entry = entry; - this.reference = null; - } - - public ClassReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference reference) { - this.deobfuscatingTranslator = deobfuscatingTranslator; - this.entry = reference.entry; - this.reference = reference; - } - - @Override - public ClassEntry getEntry() { - return this.entry; - } - - @Override - public EntryReference getReference() { - return this.reference; - } - - @Override - public String toString() { - if (this.reference != null) { - return String.format("%s", this.deobfuscatingTranslator.translate(this.reference.context)); - } - return this.deobfuscatingTranslator.translate(this.entry).getFullName(); - } - - public void load(JarIndex index, boolean recurse) { - ReferenceIndex referenceIndex = index.getReferenceIndex(); - - // get all the child nodes - for (EntryReference reference : referenceIndex.getReferencesToClass(this.entry)) { - add(new ClassReferenceTreeNode(this.deobfuscatingTranslator, reference)); - } - - if (recurse && this.children != null) { - for (Object child : this.children) { - if (child instanceof ClassReferenceTreeNode) { - ClassReferenceTreeNode node = (ClassReferenceTreeNode) child; - - // 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; - } - - node.load(index, true); - } - } - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/EntryReference.java b/src/main/java/cuchaz/enigma/analysis/EntryReference.java deleted file mode 100644 index 2e738c0..0000000 --- a/src/main/java/cuchaz/enigma/analysis/EntryReference.java +++ /dev/null @@ -1,140 +0,0 @@ -/******************************************************************************* - * 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.Translatable; -import cuchaz.enigma.translation.Translator; -import cuchaz.enigma.translation.mapping.EntryMapping; -import cuchaz.enigma.translation.mapping.EntryResolver; -import cuchaz.enigma.translation.mapping.EntryMap; -import cuchaz.enigma.translation.representation.entry.ClassEntry; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.translation.representation.entry.MethodEntry; -import cuchaz.enigma.utils.Utils; - -import java.util.Arrays; -import java.util.List; - -public class EntryReference, C extends Entry> implements Translatable { - - private static final List CONSTRUCTOR_NON_NAMES = Arrays.asList("this", "super", "static"); - public E entry; - public C context; - public ReferenceTargetType targetType; - - private boolean sourceName; - - public EntryReference(E entry, String sourceName) { - this(entry, sourceName, null); - } - - public EntryReference(E entry, String sourceName, C context) { - this(entry, sourceName, context, ReferenceTargetType.none()); - } - - public EntryReference(E entry, String sourceName, C context, ReferenceTargetType targetType) { - if (entry == null) { - throw new IllegalArgumentException("Entry cannot be null!"); - } - - this.entry = entry; - this.context = context; - this.targetType = targetType; - - this.sourceName = sourceName != null && !sourceName.isEmpty(); - if (entry instanceof MethodEntry && ((MethodEntry) entry).isConstructor() && CONSTRUCTOR_NON_NAMES.contains(sourceName)) { - this.sourceName = false; - } - } - - public EntryReference(E entry, C context, EntryReference other) { - this.entry = entry; - this.context = context; - this.sourceName = other.sourceName; - this.targetType = other.targetType; - } - - public ClassEntry getLocationClassEntry() { - if (context != null) { - return context.getContainingClass(); - } - return entry.getContainingClass(); - } - - public boolean isNamed() { - return this.sourceName; - } - - public Entry getNameableEntry() { - if (entry instanceof MethodEntry && ((MethodEntry) entry).isConstructor()) { - // renaming a constructor really means renaming the class - return entry.getContainingClass(); - } - return entry; - } - - public String getNameableName() { - return getNameableEntry().getName(); - } - - @Override - public int hashCode() { - if (context != null) { - return Utils.combineHashesOrdered(entry.hashCode(), context.hashCode()); - } - return entry.hashCode(); - } - - @Override - public boolean equals(Object other) { - return other instanceof EntryReference && equals((EntryReference) other); - } - - public boolean equals(EntryReference other) { - // check entry first - boolean isEntrySame = entry.equals(other.entry); - if (!isEntrySame) { - return false; - } - - // check caller - if (context == null && other.context == null) { - return true; - } else if (context != null && other.context != null) { - return context.equals(other.context); - } - return false; - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append(entry); - - if (context != null) { - buf.append(" called from "); - buf.append(context); - } - - if (targetType != null && targetType.getKind() != ReferenceTargetType.Kind.NONE) { - buf.append(" on target of type "); - buf.append(targetType); - } - - return buf.toString(); - } - - @Override - public Translatable translate(Translator translator, EntryResolver resolver, EntryMap mappings) { - return new EntryReference<>(translator.translate(entry), translator.translate(context), this); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java deleted file mode 100644 index 4beab7f..0000000 --- a/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - * 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.analysis.index.JarIndex; -import cuchaz.enigma.analysis.index.ReferenceIndex; -import cuchaz.enigma.translation.Translator; -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; - - public FieldReferenceTreeNode(Translator translator, FieldEntry entry) { - this.translator = translator; - this.entry = entry; - this.reference = null; - } - - private FieldReferenceTreeNode(Translator translator, EntryReference reference) { - this.translator = translator; - this.entry = reference.entry; - this.reference = reference; - } - - @Override - public FieldEntry getEntry() { - return this.entry; - } - - @Override - public EntryReference getReference() { - return this.reference; - } - - @Override - public String toString() { - if (this.reference != null) { - return String.format("%s", translator.translate(this.reference.context)); - } - return translator.translate(entry).toString(); - } - - public void load(JarIndex index, boolean recurse) { - ReferenceIndex referenceIndex = index.getReferenceIndex(); - - // get all the child nodes - if (this.reference == null) { - for (EntryReference reference : referenceIndex.getReferencesToField(this.entry)) { - add(new FieldReferenceTreeNode(translator, reference)); - } - } else { - for (EntryReference reference : referenceIndex.getReferencesToMethod(this.reference.context)) { - add(new MethodReferenceTreeNode(translator, reference)); - } - } - - if (recurse && children != null) { - for (Object node : children) { - if (node instanceof MethodReferenceTreeNode) { - ((MethodReferenceTreeNode) node).load(index, true, false); - } else if (node instanceof FieldReferenceTreeNode) { - ((FieldReferenceTreeNode) node).load(index, true); - } - } - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java b/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java deleted file mode 100644 index 80a7154..0000000 --- a/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java +++ /dev/null @@ -1,154 +0,0 @@ -package cuchaz.enigma.analysis; - -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 cuchaz.enigma.utils.Utils; -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(Utils.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/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java b/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java deleted file mode 100644 index 0c2dfd7..0000000 --- a/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java +++ /dev/null @@ -1,74 +0,0 @@ -package cuchaz.enigma.analysis; - -import com.google.common.collect.Lists; -import cuchaz.enigma.analysis.index.JarIndex; -import cuchaz.enigma.translation.Translator; -import cuchaz.enigma.translation.mapping.EntryResolver; -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; - - public IndexTreeBuilder(JarIndex index) { - this.index = index; - } - - public ClassInheritanceTreeNode buildClassInheritance(Translator translator, ClassEntry obfClassEntry) { - // get the root node - List ancestry = Lists.newArrayList(); - ancestry.add(obfClassEntry.getFullName()); - for (ClassEntry classEntry : index.getInheritanceIndex().getAncestors(obfClassEntry)) { - ancestry.add(classEntry.getFullName()); - } - - ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode(translator, ancestry.get(ancestry.size() - 1)); - - // expand all children recursively - rootNode.load(index.getInheritanceIndex(), true); - - return rootNode; - } - - public ClassImplementationsTreeNode buildClassImplementations(Translator translator, ClassEntry obfClassEntry) { - if (index.getInheritanceIndex().isParent(obfClassEntry)) { - ClassImplementationsTreeNode node = new ClassImplementationsTreeNode(translator, obfClassEntry); - node.load(index); - return node; - } - return null; - } - - public MethodInheritanceTreeNode buildMethodInheritance(Translator translator, MethodEntry obfMethodEntry) { - 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) - ); - - // expand the full tree - rootNode.load(index); - - return rootNode; - } - - public List buildMethodImplementations(Translator translator, MethodEntry obfMethodEntry) { - EntryResolver resolver = index.getEntryResolver(); - 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); - nodes.add(node); - } - - return nodes; - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java b/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java deleted file mode 100644 index 8a1c238..0000000 --- a/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java +++ /dev/null @@ -1,131 +0,0 @@ -package cuchaz.enigma.analysis; - -import cuchaz.enigma.utils.Utils; -import org.objectweb.asm.Opcodes; -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 java.util.stream.Collectors; - -public class InterpreterPair extends Interpreter> { - private final Interpreter left; - private final Interpreter right; - - public InterpreterPair(Interpreter left, Interpreter right) { - super(Utils.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> values) throws AnalyzerException { - return pair( - left.naryOperation(insn, values.stream().map(v -> v.left).collect(Collectors.toList())), - right.naryOperation(insn, values.stream().map(v -> v.right).collect(Collectors.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 && Objects.equals(left, ((PairValue) o).left) && Objects.equals(right, ((PairValue) o).right); - } - - @Override - public int hashCode() { - return left.hashCode() * 31 + right.hashCode(); - } - - @Override - public int getSize() { - return (left == null ? right : left).getSize(); - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java deleted file mode 100644 index b09f7ac..0000000 --- a/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * 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 com.google.common.collect.Lists; -import cuchaz.enigma.analysis.index.EntryIndex; -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 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!"); - } - - this.entry = entry; - } - - public static MethodImplementationsTreeNode findNode(MethodImplementationsTreeNode node, MethodEntry entry) { - // is this the node? - if (node.getMethodEntry().equals(entry)) { - return node; - } - - // recurse - for (int i = 0; i < node.getChildCount(); i++) { - MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode) node.getChildAt(i), entry); - if (foundNode != null) { - return foundNode; - } - } - return null; - } - - public MethodEntry getMethodEntry() { - return this.entry; - } - - @Override - public String toString() { - MethodEntry translatedEntry = translator.translate(entry); - String className = translatedEntry.getParent().getFullName(); - String methodName = translatedEntry.getName(); - return className + "." + methodName + "()"; - } - - public void load(JarIndex index) { - // get all method implementations - List nodes = Lists.newArrayList(); - EntryIndex entryIndex = index.getEntryIndex(); - 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)); - } - } - - // add them to this node - nodes.forEach(this::add); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java deleted file mode 100644 index e77b5cc..0000000 --- a/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ /dev/null @@ -1,95 +0,0 @@ -/******************************************************************************* - * 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.analysis.index.EntryIndex; -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; - -public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { - - private final Translator translator; - private MethodEntry entry; - private boolean implemented; - - public MethodInheritanceTreeNode(Translator translator, MethodEntry entry, boolean implemented) { - this.translator = translator; - this.entry = entry; - this.implemented = implemented; - } - - public static MethodInheritanceTreeNode findNode(MethodInheritanceTreeNode node, MethodEntry entry) { - // is this the node? - if (node.getMethodEntry().equals(entry)) { - return node; - } - - // recurse - for (int i = 0; i < node.getChildCount(); i++) { - MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode) node.getChildAt(i), entry); - if (foundNode != null) { - return foundNode; - } - } - return null; - } - - public MethodEntry getMethodEntry() { - return this.entry; - } - - public boolean isImplemented() { - return this.implemented; - } - - @Override - public String toString() { - MethodEntry translatedEntry = translator.translate(entry); - String className = translatedEntry.getContainingClass().getFullName(); - - if (!this.implemented) { - return className; - } else { - String methodName = translatedEntry.getName(); - return className + "." + methodName + "()"; - } - } - - /** - * Returns true if there is sub-node worthy to display. - */ - public boolean load(JarIndex index) { - // get all the child nodes - EntryIndex entryIndex = index.getEntryIndex(); - 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()); - - MethodInheritanceTreeNode node = new MethodInheritanceTreeNode(translator, methodEntry, entryIndex.hasMethod(methodEntry)); - boolean childOverride = node.load(index); - - if (childOverride || node.implemented) { - this.add(node); - ret = true; - } - } - - return ret; - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java b/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java deleted file mode 100644 index 8117103..0000000 --- a/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java +++ /dev/null @@ -1,19 +0,0 @@ -package cuchaz.enigma.analysis; - -import org.objectweb.asm.tree.MethodNode; - -import java.util.function.Consumer; - -public class MethodNodeWithAction extends MethodNode { - 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; - } - - @Override - public void visitEnd() { - action.accept(this); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java deleted file mode 100644 index 8995eb5..0000000 --- a/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************************* - * 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 com.google.common.collect.Sets; -import cuchaz.enigma.analysis.index.JarIndex; -import cuchaz.enigma.analysis.index.ReferenceIndex; -import cuchaz.enigma.translation.Translator; -import cuchaz.enigma.translation.mapping.EntryResolver; -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; - - public MethodReferenceTreeNode(Translator translator, MethodEntry entry) { - this.translator = translator; - this.entry = entry; - this.reference = null; - } - - public MethodReferenceTreeNode(Translator translator, EntryReference reference) { - this.translator = translator; - this.entry = reference.entry; - this.reference = reference; - } - - @Override - public MethodEntry getEntry() { - return this.entry; - } - - @Override - public EntryReference getReference() { - return this.reference; - } - - @Override - public String toString() { - if (this.reference != null) { - return String.format("%s", translator.translate(this.reference.context)); - } - return translator.translate(this.entry).getName(); - } - - public void load(JarIndex index, boolean recurse, boolean recurseMethod) { - // get all the child nodes - Collection> references = getReferences(index, recurseMethod); - - for (EntryReference reference : references) { - add(new MethodReferenceTreeNode(translator, reference)); - } - - if (recurse && this.children != null) { - for (Object child : this.children) { - if (child instanceof MethodReferenceTreeNode) { - MethodReferenceTreeNode node = (MethodReferenceTreeNode) child; - - // 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; - } - - node.load(index, true, false); - } - } - } - } - - private Collection> getReferences(JarIndex index, boolean recurseMethod) { - ReferenceIndex referenceIndex = index.getReferenceIndex(); - - if (recurseMethod) { - Collection> references = new ArrayList<>(); - - EntryResolver entryResolver = index.getEntryResolver(); - for (MethodEntry methodEntry : entryResolver.resolveEquivalentMethods(entry)) { - references.addAll(referenceIndex.getReferencesToMethod(methodEntry)); - } - - return references; - } else { - return referenceIndex.getReferencesToMethod(entry); - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java b/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java deleted file mode 100644 index 5b19d18..0000000 --- a/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java +++ /dev/null @@ -1,74 +0,0 @@ -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(); - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java deleted file mode 100644 index c0a3a75..0000000 --- a/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java +++ /dev/null @@ -1,20 +0,0 @@ -/******************************************************************************* - * 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.entry.Entry; - -public interface ReferenceTreeNode, C extends Entry> { - E getEntry(); - - EntryReference getReference(); -} diff --git a/src/main/java/cuchaz/enigma/analysis/Token.java b/src/main/java/cuchaz/enigma/analysis/Token.java deleted file mode 100644 index f0155e5..0000000 --- a/src/main/java/cuchaz/enigma/analysis/Token.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * 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; - -public class Token implements Comparable { - - public int start; - public int end; - public String text; - - public Token(int start, int end, String text) { - this.start = start; - this.end = end; - this.text = text; - } - - public int getRenameOffset(String to) { - int length = this.end - this.start; - return to.length() - length; - } - - public void rename(StringBuffer source, String to) { - int oldEnd = this.end; - this.text = to; - this.end = this.start + to.length(); - - source.replace(start, oldEnd, to); - } - - public Token move(int offset) { - Token token = new Token(this.start + offset, this.end + offset, null); - token.text = text; - return token; - } - - public boolean contains(int pos) { - return pos >= start && pos <= end; - } - - @Override - public int compareTo(Token other) { - return start - other.start; - } - - @Override - public boolean equals(Object other) { - return other instanceof Token && equals((Token) other); - } - - @Override - public int hashCode() { - return start * 37 + end; - } - - public boolean equals(Token other) { - return start == other.start && end == other.end && text.equals(other.text); - } - - @Override - public String toString() { - return String.format("[%d,%d]", start, end); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java b/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java deleted file mode 100644 index a4b1aac..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java +++ /dev/null @@ -1,156 +0,0 @@ -package cuchaz.enigma.analysis.index; - -import com.google.common.collect.Maps; -import cuchaz.enigma.translation.representation.AccessFlags; -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.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; - private final ReferenceIndex referenceIndex; - - private final Map bridgeToSpecialized = Maps.newHashMap(); - private final Map specializedToBridge = Maps.newHashMap(); - - public BridgeMethodIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex) { - this.entryIndex = entryIndex; - this.inheritanceIndex = inheritanceIndex; - this.referenceIndex = referenceIndex; - } - - public void findBridgeMethods() { - // look for access and bridged methods - for (MethodEntry methodEntry : entryIndex.getMethods()) { - MethodDefEntry methodDefEntry = (MethodDefEntry) methodEntry; - - AccessFlags access = methodDefEntry.getAccess(); - if (access == null || !access.isSynthetic()) { - continue; - } - - indexSyntheticMethod(methodDefEntry, access); - } - } - - @Override - public void processIndex(JarIndex index) { - Map copiedAccessToBridge = new HashMap<>(specializedToBridge); - - for (Map.Entry entry : copiedAccessToBridge.entrySet()) { - MethodEntry specializedEntry = entry.getKey(); - MethodEntry bridgeEntry = entry.getValue(); - if (bridgeEntry.getName().equals(specializedEntry.getName())) { - continue; - } - - MethodEntry renamedSpecializedEntry = specializedEntry.withName(bridgeEntry.getName()); - specializedToBridge.put(renamedSpecializedEntry, specializedToBridge.get(specializedEntry)); - } - } - - private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) { - MethodEntry specializedMethod = findSpecializedMethod(syntheticMethod); - if (specializedMethod == null) { - return; - } - - if (access.isBridge() || isPotentialBridge(syntheticMethod, specializedMethod)) { - bridgeToSpecialized.put(syntheticMethod, specializedMethod); - specializedToBridge.put(specializedMethod, syntheticMethod); - } - } - - private MethodEntry findSpecializedMethod(MethodEntry method) { - // we want to find all compiler-added methods that directly call another with no processing - - // get all the methods that we call - final Collection referencedMethods = referenceIndex.getMethodsReferencedBy(method); - - // is there just one? - if (referencedMethods.size() != 1) { - return null; - } - - return referencedMethods.stream().findFirst().orElse(null); - } - - 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; - } - - MethodDescriptor bridgeDesc = bridgeMethod.getDesc(); - MethodDescriptor specializedDesc = specializedMethod.getDesc(); - List bridgeArguments = bridgeDesc.getArgumentDescs(); - List specializedArguments = specializedDesc.getArgumentDescs(); - - // A bridge method will always have the same number of arguments - if (bridgeArguments.size() != specializedArguments.size()) { - return false; - } - - // Check that all argument types are bridge-compatible - for (int i = 0; i < bridgeArguments.size(); i++) { - if (!areTypesBridgeCompatible(bridgeArguments.get(i), specializedArguments.get(i))) { - return false; - } - } - - // Check that the return type is bridge-compatible - return areTypesBridgeCompatible(bridgeDesc.getReturnDesc(), specializedDesc.getReturnDesc()); - } - - private boolean areTypesBridgeCompatible(TypeDescriptor bridgeDesc, TypeDescriptor specializedDesc) { - if (bridgeDesc.equals(specializedDesc)) { - return true; - } - - // Either the descs will be equal, or they are both types and different through a generic - if (bridgeDesc.isType() && specializedDesc.isType()) { - ClassEntry bridgeType = bridgeDesc.getTypeEntry(); - ClassEntry accessedType = specializedDesc.getTypeEntry(); - - // If the given types are completely unrelated to each other, this can't be bridge compatible - InheritanceIndex.Relation relation = inheritanceIndex.computeClassRelation(accessedType, bridgeType); - return relation != InheritanceIndex.Relation.UNRELATED; - } - - return false; - } - - public boolean isBridgeMethod(MethodEntry entry) { - return bridgeToSpecialized.containsKey(entry); - } - - public boolean isSpecializedMethod(MethodEntry entry) { - return specializedToBridge.containsKey(entry); - } - - @Nullable - public MethodEntry getBridgeFromSpecialized(MethodEntry specialized) { - return specializedToBridge.get(specialized); - } - - public MethodEntry getSpecializedFromBridge(MethodEntry bridge) { - return bridgeToSpecialized.get(bridge); - } - - /** Includes "renamed specialized -> bridge" entries. */ - public Map getSpecializedToBridge() { - return Collections.unmodifiableMap(specializedToBridge); - } - - /** Only "bridge -> original name" entries. **/ - public Map getBridgeToSpecialized() { - return Collections.unmodifiableMap(bridgeToSpecialized); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java b/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java deleted file mode 100644 index 9a2726e..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java +++ /dev/null @@ -1,102 +0,0 @@ -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; - -public class EntryIndex implements JarIndexer { - private Map classes = new HashMap<>(); - private Map fields = new HashMap<>(); - private Map methods = new HashMap<>(); - private Map definitions = new HashMap<>(); - - @Override - public void indexClass(ClassDefEntry classEntry) { - definitions.put(classEntry, classEntry); - classes.put(classEntry, classEntry.getAccess()); - } - - @Override - public void indexMethod(MethodDefEntry methodEntry) { - methods.put(methodEntry, methodEntry.getAccess()); - } - - @Override - public void indexField(FieldDefEntry fieldEntry) { - fields.put(fieldEntry, fieldEntry.getAccess()); - } - - public boolean hasClass(ClassEntry entry) { - return classes.containsKey(entry); - } - - public boolean hasMethod(MethodEntry entry) { - return methods.containsKey(entry); - } - - public boolean hasField(FieldEntry entry) { - return fields.containsKey(entry); - } - - public boolean hasEntry(Entry entry) { - if (entry instanceof ClassEntry) { - return hasClass((ClassEntry) entry); - } else if (entry instanceof MethodEntry) { - return hasMethod((MethodEntry) entry); - } else if (entry instanceof FieldEntry) { - return hasField((FieldEntry) entry); - } else if (entry instanceof LocalVariableEntry) { - return hasMethod(((LocalVariableEntry) entry).getParent()); - } - - return false; - } - - @Nullable - public AccessFlags getMethodAccess(MethodEntry entry) { - return methods.get(entry); - } - - @Nullable - public AccessFlags getFieldAccess(FieldEntry entry) { - return fields.get(entry); - } - - @Nullable - public AccessFlags getClassAccess(ClassEntry entry) { - return classes.get(entry); - } - - @Nullable - public AccessFlags getEntryAccess(Entry entry) { - if (entry instanceof MethodEntry) { - return getMethodAccess((MethodEntry) entry); - } else if (entry instanceof FieldEntry) { - return getFieldAccess((FieldEntry) entry); - } else if (entry instanceof LocalVariableEntry) { - return getMethodAccess(((LocalVariableEntry) entry).getParent()); - } - - return null; - } - - public ClassDefEntry getDefinition(ClassEntry entry) { - return definitions.get(entry); - } - - public Collection getClasses() { - return classes.keySet(); - } - - public Collection getMethods() { - return methods.keySet(); - } - - public Collection getFields() { - return fields.keySet(); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java b/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java deleted file mode 100644 index f9cb23c..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java +++ /dev/null @@ -1,40 +0,0 @@ -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; - -public class IndexClassVisitor extends ClassVisitor { - private final JarIndexer indexer; - private ClassDefEntry classEntry; - - public IndexClassVisitor(JarIndex indexer, int api) { - super(api); - this.indexer = indexer; - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - classEntry = ClassDefEntry.parse(access, name, signature, superName, interfaces); - indexer.indexClass(classEntry); - - super.visit(version, access, name, signature, superName, interfaces); - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { - indexer.indexField(FieldDefEntry.parse(classEntry, access, name, desc, signature)); - - return super.visitField(access, name, desc, signature, value); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - indexer.indexMethod(MethodDefEntry.parse(classEntry, access, name, desc, signature)); - - return super.visitMethod(access, name, desc, signature, exceptions); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java b/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java deleted file mode 100644 index f3d419e..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java +++ /dev/null @@ -1,180 +0,0 @@ -package cuchaz.enigma.analysis.index; - -import cuchaz.enigma.analysis.IndexSimpleVerifier; -import cuchaz.enigma.analysis.InterpreterPair; -import cuchaz.enigma.analysis.MethodNodeWithAction; -import cuchaz.enigma.analysis.ReferenceTargetType; -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 java.util.stream.Collectors; - -public class IndexReferenceVisitor extends ClassVisitor { - private final JarIndexer indexer; - private final EntryIndex entryIndex; - private final InheritanceIndex inheritanceIndex; - private ClassEntry classEntry; - private String className; - - public IndexReferenceVisitor(JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex, int api) { - super(api); - this.indexer = indexer; - this.entryIndex = entryIndex; - this.inheritanceIndex = inheritanceIndex; - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - classEntry = new ClassEntry(name); - className = name; - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - MethodDefEntry entry = new MethodDefEntry(classEntry, name, new MethodDescriptor(desc), Signature.createSignature(signature), new AccessFlags(access)); - return new MethodNodeWithAction(api, access, name, desc, signature, exceptions, methodNode -> { - try { - new Analyzer<>(new MethodInterpreter(entry, indexer, entryIndex, inheritanceIndex)).analyze(className, methodNode); - } catch (AnalyzerException e) { - throw new RuntimeException(e); - } - }); - } - - private static class MethodInterpreter extends InterpreterPair { - private final MethodDefEntry callerEntry; - private JarIndexer indexer; - - public MethodInterpreter(MethodDefEntry callerEntry, JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex) { - super(new IndexSimpleVerifier(entryIndex, inheritanceIndex), new SourceInterpreter()); - this.callerEntry = callerEntry; - this.indexer = indexer; - } - - @Override - public PairValue newOperation(AbstractInsnNode insn) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.GETSTATIC) { - FieldInsnNode field = (FieldInsnNode) insn; - indexer.indexFieldReference(callerEntry, FieldEntry.parse(field.owner, field.name, field.desc), ReferenceTargetType.none()); - } - - return super.newOperation(insn); - } - - @Override - public PairValue unaryOperation(AbstractInsnNode insn, PairValue value) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.PUTSTATIC) { - FieldInsnNode field = (FieldInsnNode) insn; - indexer.indexFieldReference(callerEntry, FieldEntry.parse(field.owner, field.name, field.desc), ReferenceTargetType.none()); - } - - if (insn.getOpcode() == Opcodes.GETFIELD) { - FieldInsnNode field = (FieldInsnNode) insn; - indexer.indexFieldReference(callerEntry, FieldEntry.parse(field.owner, field.name, field.desc), getReferenceTargetType(value, insn)); - } - - return super.unaryOperation(insn, value); - } - - - @Override - public PairValue binaryOperation(AbstractInsnNode insn, PairValue value1, PairValue value2) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.PUTFIELD) { - FieldInsnNode field = (FieldInsnNode) insn; - FieldEntry fieldEntry = FieldEntry.parse(field.owner, field.name, field.desc); - indexer.indexFieldReference(callerEntry, fieldEntry, ReferenceTargetType.none()); - } - - return super.binaryOperation(insn, value1, value2); - } - - @Override - public PairValue naryOperation(AbstractInsnNode insn, List> values) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.INVOKEINTERFACE || insn.getOpcode() == Opcodes.INVOKESPECIAL || insn.getOpcode() == Opcodes.INVOKEVIRTUAL) { - MethodInsnNode methodInsn = (MethodInsnNode) insn; - indexer.indexMethodReference(callerEntry, MethodEntry.parse(methodInsn.owner, methodInsn.name, methodInsn.desc), getReferenceTargetType(values.get(0), insn)); - } - - if (insn.getOpcode() == Opcodes.INVOKESTATIC) { - MethodInsnNode methodInsn = (MethodInsnNode) insn; - indexer.indexMethodReference(callerEntry, MethodEntry.parse(methodInsn.owner, methodInsn.name, methodInsn.desc), ReferenceTargetType.none()); - } - - if (insn.getOpcode() == Opcodes.INVOKEDYNAMIC) { - InvokeDynamicInsnNode invokeDynamicInsn = (InvokeDynamicInsnNode) insn; - List args = values.stream().map(v -> v.right.insns.stream().findFirst().orElseThrow(AssertionError::new)).collect(Collectors.toList()); - - if ("java/lang/invoke/LambdaMetafactory".equals(invokeDynamicInsn.bsm.getOwner()) && "metafactory".equals(invokeDynamicInsn.bsm.getName())) { - Type samMethodType = (Type) invokeDynamicInsn.bsmArgs[0]; - Handle implMethod = (Handle) invokeDynamicInsn.bsmArgs[1]; - 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); - } else { - targetType = ReferenceTargetType.none(); // no "this" argument - } - } else { - 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); - } - } - - return super.naryOperation(insn, values); - } - - private ReferenceTargetType getReferenceTargetType(PairValue target, AbstractInsnNode insn) throws AnalyzerException { - if (target.left == BasicValue.UNINITIALIZED_VALUE) { - return ReferenceTargetType.uninitialized(); - } - - if (target.left.getType().getSort() == Type.OBJECT) { - return ReferenceTargetType.classType(new ClassEntry(target.left.getType().getInternalName())); - } - - if (target.left.getType().getSort() == Type.ARRAY) { - return ReferenceTargetType.classType(new ClassEntry("java/lang/Object")); - } - - throw new AnalyzerException(insn, "called method on or accessed field of non-object type"); - } - - 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()); - } - - throw new RuntimeException("Invalid handle tag " + handle.getTag()); - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java b/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java deleted file mode 100644 index 1ab2abd..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java +++ /dev/null @@ -1,127 +0,0 @@ -/******************************************************************************* - * 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.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; - - private Multimap classParents = HashMultimap.create(); - private Multimap classChildren = HashMultimap.create(); - - public InheritanceIndex(EntryIndex entryIndex) { - this.entryIndex = entryIndex; - } - - @Override - public void indexClass(ClassDefEntry classEntry) { - if (classEntry.isJre()) { - return; - } - - ClassEntry superClass = classEntry.getSuperClass(); - if (superClass != null && !superClass.getName().equals("java/lang/Object")) { - indexParent(classEntry, superClass); - } - - for (ClassEntry interfaceEntry : classEntry.getInterfaces()) { - indexParent(classEntry, interfaceEntry); - } - } - - private void indexParent(ClassEntry childEntry, ClassEntry parentEntry) { - classParents.put(childEntry, parentEntry); - classChildren.put(parentEntry, childEntry); - } - - public Collection getParents(ClassEntry classEntry) { - return classParents.get(classEntry); - } - - public Collection getChildren(ClassEntry classEntry) { - return classChildren.get(classEntry); - } - - public Collection getDescendants(ClassEntry classEntry) { - Collection descendants = new HashSet<>(); - - LinkedList descendantQueue = new LinkedList<>(); - descendantQueue.push(classEntry); - - while (!descendantQueue.isEmpty()) { - ClassEntry descendant = descendantQueue.pop(); - Collection children = getChildren(descendant); - - children.forEach(descendantQueue::push); - descendants.addAll(children); - } - - return descendants; - } - - public Set getAncestors(ClassEntry classEntry) { - Set ancestors = Sets.newHashSet(); - - LinkedList ancestorQueue = new LinkedList<>(); - ancestorQueue.push(classEntry); - - while (!ancestorQueue.isEmpty()) { - ClassEntry ancestor = ancestorQueue.pop(); - Collection parents = getParents(ancestor); - - parents.forEach(ancestorQueue::push); - ancestors.addAll(parents); - } - - return ancestors; - } - - public Relation computeClassRelation(ClassEntry classEntry, ClassEntry potentialAncestor) { - 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)) { - return Relation.RELATED; - } else if (!entryIndex.hasClass(ancestor)) { - return Relation.UNKNOWN; - } - } - - return Relation.UNRELATED; - } - - public boolean isParent(ClassEntry classEntry) { - return classChildren.containsKey(classEntry); - } - - public boolean hasParents(ClassEntry classEntry) { - Collection parents = classParents.get(classEntry); - return parents != null && !parents.isEmpty(); - } - - public enum Relation { - RELATED, - UNRELATED, - UNKNOWN - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java deleted file mode 100644 index e401c2f..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - * 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.HashMultimap; -import com.google.common.collect.Multimap; -import cuchaz.enigma.ProgressListener; -import cuchaz.enigma.analysis.ClassCache; -import cuchaz.enigma.analysis.ReferenceTargetType; -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.utils.I18n; - -import cuchaz.enigma.utils.Utils; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.Opcodes; - -import java.util.Arrays; -import java.util.Collection; - -public class JarIndex implements JarIndexer { - private final EntryIndex entryIndex; - private final InheritanceIndex inheritanceIndex; - private final ReferenceIndex referenceIndex; - private final BridgeMethodIndex bridgeMethodIndex; - private final PackageVisibilityIndex packageVisibilityIndex; - private final EntryResolver entryResolver; - - private final Collection indexers; - - private final Multimap methodImplementations = HashMultimap.create(); - - public JarIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex, BridgeMethodIndex bridgeMethodIndex, PackageVisibilityIndex packageVisibilityIndex) { - this.entryIndex = entryIndex; - this.inheritanceIndex = inheritanceIndex; - this.referenceIndex = referenceIndex; - this.bridgeMethodIndex = bridgeMethodIndex; - this.packageVisibilityIndex = packageVisibilityIndex; - this.indexers = Arrays.asList(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex); - this.entryResolver = new IndexEntryResolver(this); - } - - public static JarIndex empty() { - EntryIndex entryIndex = new EntryIndex(); - InheritanceIndex inheritanceIndex = new InheritanceIndex(entryIndex); - ReferenceIndex referenceIndex = new ReferenceIndex(); - BridgeMethodIndex bridgeMethodIndex = new BridgeMethodIndex(entryIndex, inheritanceIndex, referenceIndex); - PackageVisibilityIndex packageVisibilityIndex = new PackageVisibilityIndex(); - return new JarIndex(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex); - } - - public void indexJar(ClassCache classCache, ProgressListener progress) { - progress.init(4, I18n.translate("progress.jar.indexing")); - - progress.step(1, I18n.translate("progress.jar.indexing.entries")); - classCache.visit(() -> new IndexClassVisitor(this, Utils.ASM_VERSION), ClassReader.SKIP_CODE); - - progress.step(2, I18n.translate("progress.jar.indexing.references")); - classCache.visit(() -> new IndexReferenceVisitor(this, entryIndex, inheritanceIndex, Utils.ASM_VERSION), 0); - - progress.step(3, I18n.translate("progress.jar.indexing.methods")); - bridgeMethodIndex.findBridgeMethods(); - - progress.step(4, I18n.translate("progress.jar.indexing.process")); - processIndex(this); - } - - @Override - public void processIndex(JarIndex index) { - indexers.forEach(indexer -> indexer.processIndex(index)); - } - - @Override - public void indexClass(ClassDefEntry classEntry) { - if (classEntry.isJre()) { - return; - } - - for (ClassEntry interfaceEntry : classEntry.getInterfaces()) { - if (classEntry.equals(interfaceEntry)) { - throw new IllegalArgumentException("Class cannot be its own interface! " + classEntry); - } - } - - indexers.forEach(indexer -> indexer.indexClass(classEntry)); - } - - @Override - public void indexField(FieldDefEntry fieldEntry) { - if (fieldEntry.getParent().isJre()) { - return; - } - - indexers.forEach(indexer -> indexer.indexField(fieldEntry)); - } - - @Override - public void indexMethod(MethodDefEntry methodEntry) { - if (methodEntry.getParent().isJre()) { - return; - } - - indexers.forEach(indexer -> indexer.indexMethod(methodEntry)); - - if (!methodEntry.isConstructor()) { - methodImplementations.put(methodEntry.getParent().getFullName(), methodEntry); - } - } - - @Override - public void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry, ReferenceTargetType targetType) { - if (callerEntry.getParent().isJre()) { - return; - } - - indexers.forEach(indexer -> indexer.indexMethodReference(callerEntry, referencedEntry, targetType)); - } - - @Override - public void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry, ReferenceTargetType targetType) { - if (callerEntry.getParent().isJre()) { - return; - } - - indexers.forEach(indexer -> indexer.indexFieldReference(callerEntry, referencedEntry, targetType)); - } - - @Override - public void indexLambda(MethodDefEntry callerEntry, Lambda lambda, ReferenceTargetType targetType) { - if (callerEntry.getParent().isJre()) { - return; - } - - indexers.forEach(indexer -> indexer.indexLambda(callerEntry, lambda, targetType)); - } - - public EntryIndex getEntryIndex() { - return entryIndex; - } - - public InheritanceIndex getInheritanceIndex() { - return this.inheritanceIndex; - } - - public ReferenceIndex getReferenceIndex() { - return referenceIndex; - } - - public BridgeMethodIndex getBridgeMethodIndex() { - return bridgeMethodIndex; - } - - public PackageVisibilityIndex getPackageVisibilityIndex() { - return packageVisibilityIndex; - } - - public EntryResolver getEntryResolver() { - return entryResolver; - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java deleted file mode 100644 index f17e7c9..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java +++ /dev/null @@ -1,28 +0,0 @@ -package cuchaz.enigma.analysis.index; - -import cuchaz.enigma.analysis.ReferenceTargetType; -import cuchaz.enigma.translation.representation.Lambda; -import cuchaz.enigma.translation.representation.entry.*; - -public interface JarIndexer { - default void indexClass(ClassDefEntry classEntry) { - } - - default void indexField(FieldDefEntry fieldEntry) { - } - - default void indexMethod(MethodDefEntry methodEntry) { - } - - default void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry, ReferenceTargetType targetType) { - } - - default void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry, ReferenceTargetType targetType) { - } - - default void indexLambda(MethodDefEntry callerEntry, Lambda lambda, ReferenceTargetType targetType) { - } - - default void processIndex(JarIndex index) { - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java b/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java deleted file mode 100644 index 63eb730..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java +++ /dev/null @@ -1,147 +0,0 @@ -package cuchaz.enigma.analysis.index; - -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.*; - -public class PackageVisibilityIndex implements JarIndexer { - private static boolean requiresSamePackage(AccessFlags entryAcc, EntryReference ref, InheritanceIndex inheritanceIndex) { - if (entryAcc.isPublic()) { - return false; - } - - if (entryAcc.isProtected()) { - ClassEntry contextClass = ref.context.getContainingClass(); - ClassEntry referencedClass = ref.entry.getContainingClass(); - - if (!inheritanceIndex.getAncestors(contextClass).contains(referencedClass)) { - return true; // access to protected member not in superclass - } - - if (ref.targetType.getKind() == ReferenceTargetType.Kind.NONE) { - return false; // access to superclass or static superclass member - } - - // 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 true; - } - - private final HashMultimap connections = HashMultimap.create(); - private final List> partitions = Lists.newArrayList(); - private final Map> classPartitions = Maps.newHashMap(); - - private void addConnection(ClassEntry classA, ClassEntry classB) { - if (classA != classB) { - connections.put(classA, classB); - connections.put(classB, classA); - } - } - - private void buildPartition(Set unassignedClasses, Set partition, ClassEntry member) { - for (ClassEntry connected : connections.get(member)) { - if (unassignedClasses.remove(connected)) { - partition.add(connected); - buildPartition(unassignedClasses, partition, connected); - } - } - } - - 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)) { - addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); - } - } - } - } - - 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)) { - addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); - } - } - } - } - - 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)) { - addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); - } - } - - for (EntryReference ref : referenceIndex.getMethodTypeReferencesToClass(entry)) { - if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { - addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); - } - } - } - - 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); - } - } - } - - private void addPartitions(EntryIndex entryIndex) { - Set unassignedClasses = Sets.newHashSet(entryIndex.getClasses()); - while (!unassignedClasses.isEmpty()) { - Iterator iterator = unassignedClasses.iterator(); - ClassEntry initialEntry = iterator.next(); - iterator.remove(); - - HashSet partition = Sets.newHashSet(); - partition.add(initialEntry); - buildPartition(unassignedClasses, partition, initialEntry); - partitions.add(partition); - for (ClassEntry entry : partition) { - classPartitions.put(entry, partition); - } - } - } - - public Collection> getPartitions() { - return partitions; - } - - public Set getPartition(ClassEntry classEntry) { - return classPartitions.get(classEntry); - } - - @Override - public void processIndex(JarIndex index) { - EntryIndex entryIndex = index.getEntryIndex(); - ReferenceIndex referenceIndex = index.getReferenceIndex(); - InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); - addConnections(entryIndex, referenceIndex, inheritanceIndex); - addPartitions(entryIndex); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java b/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java deleted file mode 100644 index b6797c2..0000000 --- a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java +++ /dev/null @@ -1,148 +0,0 @@ -package cuchaz.enigma.analysis.index; - -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; - -public class ReferenceIndex implements JarIndexer { - private Multimap methodReferences = HashMultimap.create(); - - private Multimap> referencesToMethods = HashMultimap.create(); - private Multimap> referencesToClasses = HashMultimap.create(); - private Multimap> referencesToFields = HashMultimap.create(); - private Multimap> fieldTypeReferences = HashMultimap.create(); - private Multimap> methodTypeReferences = HashMultimap.create(); - - @Override - public void indexMethod(MethodDefEntry methodEntry) { - indexMethodDescriptor(methodEntry, methodEntry.getDesc()); - } - - private void indexMethodDescriptor(MethodDefEntry entry, MethodDescriptor descriptor) { - for (TypeDescriptor typeDescriptor : descriptor.getArgumentDescs()) { - indexMethodTypeDescriptor(entry, typeDescriptor); - } - indexMethodTypeDescriptor(entry, descriptor.getReturnDesc()); - } - - private void indexMethodTypeDescriptor(MethodDefEntry method, TypeDescriptor typeDescriptor) { - if (typeDescriptor.isType()) { - ClassEntry referencedClass = typeDescriptor.getTypeEntry(); - methodTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), method)); - } else if (typeDescriptor.isArray()) { - indexMethodTypeDescriptor(method, typeDescriptor.getArrayType()); - } - } - - @Override - public void indexField(FieldDefEntry fieldEntry) { - indexFieldTypeDescriptor(fieldEntry, fieldEntry.getDesc()); - } - - private void indexFieldTypeDescriptor(FieldDefEntry field, TypeDescriptor typeDescriptor) { - if (typeDescriptor.isType()) { - ClassEntry referencedClass = typeDescriptor.getTypeEntry(); - fieldTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), field)); - } else if (typeDescriptor.isArray()) { - indexFieldTypeDescriptor(field, typeDescriptor.getArrayType()); - } - } - - @Override - public void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry, ReferenceTargetType targetType) { - referencesToMethods.put(referencedEntry, new EntryReference<>(referencedEntry, referencedEntry.getName(), callerEntry, targetType)); - methodReferences.put(callerEntry, referencedEntry); - - if (referencedEntry.isConstructor()) { - ClassEntry referencedClass = referencedEntry.getParent(); - referencesToClasses.put(referencedClass, new EntryReference<>(referencedClass, referencedEntry.getName(), callerEntry, targetType)); - } - } - - @Override - public void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry, ReferenceTargetType targetType) { - referencesToFields.put(referencedEntry, new EntryReference<>(referencedEntry, referencedEntry.getName(), callerEntry, targetType)); - } - - @Override - public void indexLambda(MethodDefEntry callerEntry, Lambda lambda, ReferenceTargetType targetType) { - if (lambda.getImplMethod() instanceof MethodEntry) { - indexMethodReference(callerEntry, (MethodEntry) lambda.getImplMethod(), targetType); - } else { - indexFieldReference(callerEntry, (FieldEntry) lambda.getImplMethod(), targetType); - } - - indexMethodDescriptor(callerEntry, lambda.getInvokedType()); - indexMethodDescriptor(callerEntry, lambda.getSamMethodType()); - indexMethodDescriptor(callerEntry, lambda.getInstantiatedMethodType()); - } - - @Override - public void processIndex(JarIndex index) { - methodReferences = remapReferences(index, methodReferences); - referencesToMethods = remapReferencesTo(index, referencesToMethods); - referencesToClasses = remapReferencesTo(index, referencesToClasses); - referencesToFields = remapReferencesTo(index, referencesToFields); - fieldTypeReferences = remapReferencesTo(index, fieldTypeReferences); - methodTypeReferences = remapReferencesTo(index, methodTypeReferences); - } - - 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; - } - - private > E remap(JarIndex index, E entry) { - return index.getEntryResolver().resolveFirstEntry(entry, ResolutionStrategy.RESOLVE_CLOSEST); - } - - private , C extends Entry> EntryReference remap(JarIndex index, EntryReference reference) { - return index.getEntryResolver().resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST); - } - - public Collection getMethodsReferencedBy(MethodEntry entry) { - return methodReferences.get(entry); - } - - public Collection> getReferencesToField(FieldEntry entry) { - return referencesToFields.get(entry); - } - - public Collection> getReferencesToClass(ClassEntry entry) { - return referencesToClasses.get(entry); - } - - public Collection> getReferencesToMethod(MethodEntry entry) { - return referencesToMethods.get(entry); - } - - public Collection> getFieldTypeReferencesToClass(ClassEntry entry) { - return fieldTypeReferences.get(entry); - } - - public Collection> getMethodTypeReferencesToClass(ClassEntry entry) { - return methodTypeReferences.get(entry); - } -} -- cgit v1.2.3