diff options
| author | 2019-11-02 17:23:14 -0400 | |
|---|---|---|
| committer | 2019-11-02 21:23:14 +0000 | |
| commit | 422b10b419eb010b612931e8b250b9dd1b7424ed (patch) | |
| tree | b9c1d3a7add5b8d01d5b0196d6c29ad00273987c /src/main/java/cuchaz/enigma/analysis/index | |
| parent | Fix array class translation (#173) (diff) | |
| download | enigma-fork-422b10b419eb010b612931e8b250b9dd1b7424ed.tar.gz enigma-fork-422b10b419eb010b612931e8b250b9dd1b7424ed.tar.xz enigma-fork-422b10b419eb010b612931e8b250b9dd1b7424ed.zip | |
Check protected method/field target in visibility index (#157)
Diffstat (limited to 'src/main/java/cuchaz/enigma/analysis/index')
6 files changed, 178 insertions, 55 deletions
diff --git a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java b/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java index 31c6f54..9a2726e 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java | |||
| @@ -12,9 +12,11 @@ public class EntryIndex implements JarIndexer { | |||
| 12 | private Map<ClassEntry, AccessFlags> classes = new HashMap<>(); | 12 | private Map<ClassEntry, AccessFlags> classes = new HashMap<>(); |
| 13 | private Map<FieldEntry, AccessFlags> fields = new HashMap<>(); | 13 | private Map<FieldEntry, AccessFlags> fields = new HashMap<>(); |
| 14 | private Map<MethodEntry, AccessFlags> methods = new HashMap<>(); | 14 | private Map<MethodEntry, AccessFlags> methods = new HashMap<>(); |
| 15 | private Map<ClassEntry, ClassDefEntry> definitions = new HashMap<>(); | ||
| 15 | 16 | ||
| 16 | @Override | 17 | @Override |
| 17 | public void indexClass(ClassDefEntry classEntry) { | 18 | public void indexClass(ClassDefEntry classEntry) { |
| 19 | definitions.put(classEntry, classEntry); | ||
| 18 | classes.put(classEntry, classEntry.getAccess()); | 20 | classes.put(classEntry, classEntry.getAccess()); |
| 19 | } | 21 | } |
| 20 | 22 | ||
| @@ -82,6 +84,10 @@ public class EntryIndex implements JarIndexer { | |||
| 82 | return null; | 84 | return null; |
| 83 | } | 85 | } |
| 84 | 86 | ||
| 87 | public ClassDefEntry getDefinition(ClassEntry entry) { | ||
| 88 | return definitions.get(entry); | ||
| 89 | } | ||
| 90 | |||
| 85 | public Collection<ClassEntry> getClasses() { | 91 | public Collection<ClassEntry> getClasses() { |
| 86 | return classes.keySet(); | 92 | return classes.keySet(); |
| 87 | } | 93 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java b/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java index b730a8a..f3d419e 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java +++ b/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java | |||
| @@ -1,52 +1,162 @@ | |||
| 1 | package cuchaz.enigma.analysis.index; | 1 | package cuchaz.enigma.analysis.index; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.analysis.IndexSimpleVerifier; | ||
| 4 | import cuchaz.enigma.analysis.InterpreterPair; | ||
| 5 | import cuchaz.enigma.analysis.MethodNodeWithAction; | ||
| 6 | import cuchaz.enigma.analysis.ReferenceTargetType; | ||
| 3 | import cuchaz.enigma.translation.representation.AccessFlags; | 7 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 4 | import cuchaz.enigma.translation.representation.Lambda; | 8 | import cuchaz.enigma.translation.representation.Lambda; |
| 5 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 9 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 6 | import cuchaz.enigma.translation.representation.Signature; | 10 | import cuchaz.enigma.translation.representation.Signature; |
| 7 | import cuchaz.enigma.translation.representation.entry.*; | 11 | import cuchaz.enigma.translation.representation.entry.*; |
| 8 | import org.objectweb.asm.*; | 12 | import org.objectweb.asm.*; |
| 13 | import org.objectweb.asm.tree.AbstractInsnNode; | ||
| 14 | import org.objectweb.asm.tree.FieldInsnNode; | ||
| 15 | import org.objectweb.asm.tree.InvokeDynamicInsnNode; | ||
| 16 | import org.objectweb.asm.tree.MethodInsnNode; | ||
| 17 | import org.objectweb.asm.tree.analysis.*; | ||
| 18 | |||
| 19 | import java.util.List; | ||
| 20 | import java.util.stream.Collectors; | ||
| 9 | 21 | ||
| 10 | public class IndexReferenceVisitor extends ClassVisitor { | 22 | public class IndexReferenceVisitor extends ClassVisitor { |
| 11 | private final JarIndexer indexer; | 23 | private final JarIndexer indexer; |
| 24 | private final EntryIndex entryIndex; | ||
| 25 | private final InheritanceIndex inheritanceIndex; | ||
| 12 | private ClassEntry classEntry; | 26 | private ClassEntry classEntry; |
| 27 | private String className; | ||
| 13 | 28 | ||
| 14 | public IndexReferenceVisitor(JarIndexer indexer, int api) { | 29 | public IndexReferenceVisitor(JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex, int api) { |
| 15 | super(api); | 30 | super(api); |
| 16 | this.indexer = indexer; | 31 | this.indexer = indexer; |
| 32 | this.entryIndex = entryIndex; | ||
| 33 | this.inheritanceIndex = inheritanceIndex; | ||
| 17 | } | 34 | } |
| 18 | 35 | ||
| 19 | @Override | 36 | @Override |
| 20 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { | 37 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { |
| 21 | this.classEntry = new ClassEntry(name); | 38 | classEntry = new ClassEntry(name); |
| 39 | className = name; | ||
| 22 | } | 40 | } |
| 23 | 41 | ||
| 24 | @Override | 42 | @Override |
| 25 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { | 43 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { |
| 26 | MethodDefEntry entry = new MethodDefEntry(classEntry, name, new MethodDescriptor(desc), Signature.createSignature(signature), new AccessFlags(access)); | 44 | MethodDefEntry entry = new MethodDefEntry(classEntry, name, new MethodDescriptor(desc), Signature.createSignature(signature), new AccessFlags(access)); |
| 27 | return new Method(this.indexer, entry, this.api); | 45 | return new MethodNodeWithAction(api, access, name, desc, signature, exceptions, methodNode -> { |
| 46 | try { | ||
| 47 | new Analyzer<>(new MethodInterpreter(entry, indexer, entryIndex, inheritanceIndex)).analyze(className, methodNode); | ||
| 48 | } catch (AnalyzerException e) { | ||
| 49 | throw new RuntimeException(e); | ||
| 50 | } | ||
| 51 | }); | ||
| 28 | } | 52 | } |
| 29 | 53 | ||
| 30 | private static class Method extends MethodVisitor { | 54 | private static class MethodInterpreter extends InterpreterPair<BasicValue, SourceValue> { |
| 31 | private final JarIndexer indexer; | ||
| 32 | private final MethodDefEntry callerEntry; | 55 | private final MethodDefEntry callerEntry; |
| 56 | private JarIndexer indexer; | ||
| 33 | 57 | ||
| 34 | public Method(JarIndexer indexer, MethodDefEntry callerEntry, int api) { | 58 | public MethodInterpreter(MethodDefEntry callerEntry, JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex) { |
| 35 | super(api); | 59 | super(new IndexSimpleVerifier(entryIndex, inheritanceIndex), new SourceInterpreter()); |
| 36 | this.indexer = indexer; | ||
| 37 | this.callerEntry = callerEntry; | 60 | this.callerEntry = callerEntry; |
| 61 | this.indexer = indexer; | ||
| 38 | } | 62 | } |
| 39 | 63 | ||
| 40 | @Override | 64 | @Override |
| 41 | public void visitFieldInsn(int opcode, String owner, String name, String desc) { | 65 | public PairValue<BasicValue, SourceValue> newOperation(AbstractInsnNode insn) throws AnalyzerException { |
| 42 | FieldEntry fieldEntry = FieldEntry.parse(owner, name, desc); | 66 | if (insn.getOpcode() == Opcodes.GETSTATIC) { |
| 43 | this.indexer.indexFieldReference(callerEntry, fieldEntry); | 67 | FieldInsnNode field = (FieldInsnNode) insn; |
| 68 | indexer.indexFieldReference(callerEntry, FieldEntry.parse(field.owner, field.name, field.desc), ReferenceTargetType.none()); | ||
| 69 | } | ||
| 70 | |||
| 71 | return super.newOperation(insn); | ||
| 44 | } | 72 | } |
| 45 | 73 | ||
| 46 | @Override | 74 | @Override |
| 47 | public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { | 75 | public PairValue<BasicValue, SourceValue> unaryOperation(AbstractInsnNode insn, PairValue<BasicValue, SourceValue> value) throws AnalyzerException { |
| 48 | MethodEntry methodEntry = MethodEntry.parse(owner, name, desc); | 76 | if (insn.getOpcode() == Opcodes.PUTSTATIC) { |
| 49 | this.indexer.indexMethodReference(callerEntry, methodEntry); | 77 | FieldInsnNode field = (FieldInsnNode) insn; |
| 78 | indexer.indexFieldReference(callerEntry, FieldEntry.parse(field.owner, field.name, field.desc), ReferenceTargetType.none()); | ||
| 79 | } | ||
| 80 | |||
| 81 | if (insn.getOpcode() == Opcodes.GETFIELD) { | ||
| 82 | FieldInsnNode field = (FieldInsnNode) insn; | ||
| 83 | indexer.indexFieldReference(callerEntry, FieldEntry.parse(field.owner, field.name, field.desc), getReferenceTargetType(value, insn)); | ||
| 84 | } | ||
| 85 | |||
| 86 | return super.unaryOperation(insn, value); | ||
| 87 | } | ||
| 88 | |||
| 89 | |||
| 90 | @Override | ||
| 91 | public PairValue<BasicValue, SourceValue> binaryOperation(AbstractInsnNode insn, PairValue<BasicValue, SourceValue> value1, PairValue<BasicValue, SourceValue> value2) throws AnalyzerException { | ||
| 92 | if (insn.getOpcode() == Opcodes.PUTFIELD) { | ||
| 93 | FieldInsnNode field = (FieldInsnNode) insn; | ||
| 94 | FieldEntry fieldEntry = FieldEntry.parse(field.owner, field.name, field.desc); | ||
| 95 | indexer.indexFieldReference(callerEntry, fieldEntry, ReferenceTargetType.none()); | ||
| 96 | } | ||
| 97 | |||
| 98 | return super.binaryOperation(insn, value1, value2); | ||
| 99 | } | ||
| 100 | |||
| 101 | @Override | ||
| 102 | public PairValue<BasicValue, SourceValue> naryOperation(AbstractInsnNode insn, List<? extends PairValue<BasicValue, SourceValue>> values) throws AnalyzerException { | ||
| 103 | if (insn.getOpcode() == Opcodes.INVOKEINTERFACE || insn.getOpcode() == Opcodes.INVOKESPECIAL || insn.getOpcode() == Opcodes.INVOKEVIRTUAL) { | ||
| 104 | MethodInsnNode methodInsn = (MethodInsnNode) insn; | ||
| 105 | indexer.indexMethodReference(callerEntry, MethodEntry.parse(methodInsn.owner, methodInsn.name, methodInsn.desc), getReferenceTargetType(values.get(0), insn)); | ||
| 106 | } | ||
| 107 | |||
| 108 | if (insn.getOpcode() == Opcodes.INVOKESTATIC) { | ||
| 109 | MethodInsnNode methodInsn = (MethodInsnNode) insn; | ||
| 110 | indexer.indexMethodReference(callerEntry, MethodEntry.parse(methodInsn.owner, methodInsn.name, methodInsn.desc), ReferenceTargetType.none()); | ||
| 111 | } | ||
| 112 | |||
| 113 | if (insn.getOpcode() == Opcodes.INVOKEDYNAMIC) { | ||
| 114 | InvokeDynamicInsnNode invokeDynamicInsn = (InvokeDynamicInsnNode) insn; | ||
| 115 | List<AbstractInsnNode> args = values.stream().map(v -> v.right.insns.stream().findFirst().orElseThrow(AssertionError::new)).collect(Collectors.toList()); | ||
| 116 | |||
| 117 | if ("java/lang/invoke/LambdaMetafactory".equals(invokeDynamicInsn.bsm.getOwner()) && "metafactory".equals(invokeDynamicInsn.bsm.getName())) { | ||
| 118 | Type samMethodType = (Type) invokeDynamicInsn.bsmArgs[0]; | ||
| 119 | Handle implMethod = (Handle) invokeDynamicInsn.bsmArgs[1]; | ||
| 120 | Type instantiatedMethodType = (Type) invokeDynamicInsn.bsmArgs[2]; | ||
| 121 | |||
| 122 | ReferenceTargetType targetType; | ||
| 123 | if (implMethod.getTag() != Opcodes.H_GETSTATIC && implMethod.getTag() != Opcodes.H_PUTFIELD && implMethod.getTag() != Opcodes.H_INVOKESTATIC) { | ||
| 124 | if (instantiatedMethodType.getArgumentTypes().length < Type.getArgumentTypes(implMethod.getDesc()).length) { | ||
| 125 | targetType = getReferenceTargetType(values.get(0), insn); | ||
| 126 | } else { | ||
| 127 | targetType = ReferenceTargetType.none(); // no "this" argument | ||
| 128 | } | ||
| 129 | } else { | ||
| 130 | targetType = ReferenceTargetType.none(); | ||
| 131 | } | ||
| 132 | |||
| 133 | indexer.indexLambda(callerEntry, new Lambda( | ||
| 134 | invokeDynamicInsn.name, | ||
| 135 | new MethodDescriptor(invokeDynamicInsn.desc), | ||
| 136 | new MethodDescriptor(samMethodType.getDescriptor()), | ||
| 137 | getHandleEntry(implMethod), | ||
| 138 | new MethodDescriptor(instantiatedMethodType.getDescriptor()) | ||
| 139 | ), targetType); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | return super.naryOperation(insn, values); | ||
| 144 | } | ||
| 145 | |||
| 146 | private ReferenceTargetType getReferenceTargetType(PairValue<BasicValue, SourceValue> target, AbstractInsnNode insn) throws AnalyzerException { | ||
| 147 | if (target.left == BasicValue.UNINITIALIZED_VALUE) { | ||
| 148 | return ReferenceTargetType.uninitialized(); | ||
| 149 | } | ||
| 150 | |||
| 151 | if (target.left.getType().getSort() == Type.OBJECT) { | ||
| 152 | return ReferenceTargetType.classType(new ClassEntry(target.left.getType().getInternalName())); | ||
| 153 | } | ||
| 154 | |||
| 155 | if (target.left.getType().getSort() == Type.ARRAY) { | ||
| 156 | return ReferenceTargetType.classType(new ClassEntry("java/lang/Object")); | ||
| 157 | } | ||
| 158 | |||
| 159 | throw new AnalyzerException(insn, "called method on or accessed field of non-object type"); | ||
| 50 | } | 160 | } |
| 51 | 161 | ||
| 52 | private static ParentedEntry<?> getHandleEntry(Handle handle) { | 162 | private static ParentedEntry<?> getHandleEntry(Handle handle) { |
| @@ -63,24 +173,8 @@ public class IndexReferenceVisitor extends ClassVisitor { | |||
| 63 | case Opcodes.H_NEWINVOKESPECIAL: | 173 | case Opcodes.H_NEWINVOKESPECIAL: |
| 64 | return MethodEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc()); | 174 | return MethodEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc()); |
| 65 | } | 175 | } |
| 66 | throw new RuntimeException("Invalid handle tag " + handle.getTag()); | ||
| 67 | } | ||
| 68 | 176 | ||
| 69 | @Override | 177 | throw new RuntimeException("Invalid handle tag " + handle.getTag()); |
| 70 | public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { | ||
| 71 | if ("java/lang/invoke/LambdaMetafactory".equals(bsm.getOwner()) && "metafactory".equals(bsm.getName())) { | ||
| 72 | Type samMethodType = (Type) bsmArgs[0]; | ||
| 73 | Handle implMethod = (Handle) bsmArgs[1]; | ||
| 74 | Type instantiatedMethodType = (Type) bsmArgs[2]; | ||
| 75 | |||
| 76 | this.indexer.indexLambda(callerEntry, new Lambda( | ||
| 77 | name, | ||
| 78 | new MethodDescriptor(desc), | ||
| 79 | new MethodDescriptor(samMethodType.getDescriptor()), | ||
| 80 | getHandleEntry(implMethod), | ||
| 81 | new MethodDescriptor(instantiatedMethodType.getDescriptor()) | ||
| 82 | )); | ||
| 83 | } | ||
| 84 | } | 178 | } |
| 85 | } | 179 | } |
| 86 | } | 180 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java index 763282b..8e92dd8 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java | |||
| @@ -15,6 +15,7 @@ import com.google.common.collect.HashMultimap; | |||
| 15 | import com.google.common.collect.Multimap; | 15 | import com.google.common.collect.Multimap; |
| 16 | import cuchaz.enigma.ProgressListener; | 16 | import cuchaz.enigma.ProgressListener; |
| 17 | import cuchaz.enigma.analysis.ClassCache; | 17 | import cuchaz.enigma.analysis.ClassCache; |
| 18 | import cuchaz.enigma.analysis.ReferenceTargetType; | ||
| 18 | import cuchaz.enigma.translation.mapping.EntryResolver; | 19 | import cuchaz.enigma.translation.mapping.EntryResolver; |
| 19 | import cuchaz.enigma.translation.mapping.IndexEntryResolver; | 20 | import cuchaz.enigma.translation.mapping.IndexEntryResolver; |
| 20 | import cuchaz.enigma.translation.representation.Lambda; | 21 | import cuchaz.enigma.translation.representation.Lambda; |
| @@ -63,7 +64,7 @@ public class JarIndex implements JarIndexer { | |||
| 63 | classCache.visit(() -> new IndexClassVisitor(this, Opcodes.ASM5), ClassReader.SKIP_CODE); | 64 | classCache.visit(() -> new IndexClassVisitor(this, Opcodes.ASM5), ClassReader.SKIP_CODE); |
| 64 | 65 | ||
| 65 | progress.step(2, "Entry references..."); | 66 | progress.step(2, "Entry references..."); |
| 66 | classCache.visit(() -> new IndexReferenceVisitor(this, Opcodes.ASM5), ClassReader.SKIP_FRAMES); | 67 | classCache.visit(() -> new IndexReferenceVisitor(this, entryIndex, inheritanceIndex, Opcodes.ASM5), 0); |
| 67 | 68 | ||
| 68 | progress.step(3, "Bridge methods..."); | 69 | progress.step(3, "Bridge methods..."); |
| 69 | bridgeMethodIndex.findBridgeMethods(); | 70 | bridgeMethodIndex.findBridgeMethods(); |
| @@ -115,30 +116,30 @@ public class JarIndex implements JarIndexer { | |||
| 115 | } | 116 | } |
| 116 | 117 | ||
| 117 | @Override | 118 | @Override |
| 118 | public void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry) { | 119 | public void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry, ReferenceTargetType targetType) { |
| 119 | if (callerEntry.getParent().isJre()) { | 120 | if (callerEntry.getParent().isJre()) { |
| 120 | return; | 121 | return; |
| 121 | } | 122 | } |
| 122 | 123 | ||
| 123 | indexers.forEach(indexer -> indexer.indexMethodReference(callerEntry, referencedEntry)); | 124 | indexers.forEach(indexer -> indexer.indexMethodReference(callerEntry, referencedEntry, targetType)); |
| 124 | } | 125 | } |
| 125 | 126 | ||
| 126 | @Override | 127 | @Override |
| 127 | public void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry) { | 128 | public void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry, ReferenceTargetType targetType) { |
| 128 | if (callerEntry.getParent().isJre()) { | 129 | if (callerEntry.getParent().isJre()) { |
| 129 | return; | 130 | return; |
| 130 | } | 131 | } |
| 131 | 132 | ||
| 132 | indexers.forEach(indexer -> indexer.indexFieldReference(callerEntry, referencedEntry)); | 133 | indexers.forEach(indexer -> indexer.indexFieldReference(callerEntry, referencedEntry, targetType)); |
| 133 | } | 134 | } |
| 134 | 135 | ||
| 135 | @Override | 136 | @Override |
| 136 | public void indexLambda(MethodDefEntry callerEntry, Lambda lambda) { | 137 | public void indexLambda(MethodDefEntry callerEntry, Lambda lambda, ReferenceTargetType targetType) { |
| 137 | if (callerEntry.getParent().isJre()) { | 138 | if (callerEntry.getParent().isJre()) { |
| 138 | return; | 139 | return; |
| 139 | } | 140 | } |
| 140 | 141 | ||
| 141 | indexers.forEach(indexer -> indexer.indexLambda(callerEntry, lambda)); | 142 | indexers.forEach(indexer -> indexer.indexLambda(callerEntry, lambda, targetType)); |
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | public EntryIndex getEntryIndex() { | 145 | public EntryIndex getEntryIndex() { |
diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java index 4f885b3..f17e7c9 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java +++ b/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | package cuchaz.enigma.analysis.index; | 1 | package cuchaz.enigma.analysis.index; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.analysis.ReferenceTargetType; | ||
| 3 | import cuchaz.enigma.translation.representation.Lambda; | 4 | import cuchaz.enigma.translation.representation.Lambda; |
| 4 | import cuchaz.enigma.translation.representation.entry.*; | 5 | import cuchaz.enigma.translation.representation.entry.*; |
| 5 | 6 | ||
| @@ -13,13 +14,13 @@ public interface JarIndexer { | |||
| 13 | default void indexMethod(MethodDefEntry methodEntry) { | 14 | default void indexMethod(MethodDefEntry methodEntry) { |
| 14 | } | 15 | } |
| 15 | 16 | ||
| 16 | default void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry) { | 17 | default void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry, ReferenceTargetType targetType) { |
| 17 | } | 18 | } |
| 18 | 19 | ||
| 19 | default void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry) { | 20 | default void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry, ReferenceTargetType targetType) { |
| 20 | } | 21 | } |
| 21 | 22 | ||
| 22 | default void indexLambda(MethodDefEntry callerEntry, Lambda lambda) { | 23 | default void indexLambda(MethodDefEntry callerEntry, Lambda lambda, ReferenceTargetType targetType) { |
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | default void processIndex(JarIndex index) { | 26 | 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 index da28ac4..63eb730 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java | |||
| @@ -5,6 +5,7 @@ import com.google.common.collect.Lists; | |||
| 5 | import com.google.common.collect.Maps; | 5 | import com.google.common.collect.Maps; |
| 6 | import com.google.common.collect.Sets; | 6 | import com.google.common.collect.Sets; |
| 7 | import cuchaz.enigma.analysis.EntryReference; | 7 | import cuchaz.enigma.analysis.EntryReference; |
| 8 | import cuchaz.enigma.analysis.ReferenceTargetType; | ||
| 8 | import cuchaz.enigma.translation.representation.AccessFlags; | 9 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 9 | import cuchaz.enigma.translation.representation.entry.*; | 10 | import cuchaz.enigma.translation.representation.entry.*; |
| 10 | 11 | ||
| @@ -12,12 +13,29 @@ import java.util.*; | |||
| 12 | 13 | ||
| 13 | public class PackageVisibilityIndex implements JarIndexer { | 14 | public class PackageVisibilityIndex implements JarIndexer { |
| 14 | private static boolean requiresSamePackage(AccessFlags entryAcc, EntryReference ref, InheritanceIndex inheritanceIndex) { | 15 | private static boolean requiresSamePackage(AccessFlags entryAcc, EntryReference ref, InheritanceIndex inheritanceIndex) { |
| 15 | if (entryAcc.isPublic()) return false; | 16 | if (entryAcc.isPublic()) { |
| 17 | return false; | ||
| 18 | } | ||
| 19 | |||
| 16 | if (entryAcc.isProtected()) { | 20 | if (entryAcc.isProtected()) { |
| 17 | Set<ClassEntry> callerAncestors = inheritanceIndex.getAncestors(ref.context.getContainingClass()); | 21 | ClassEntry contextClass = ref.context.getContainingClass(); |
| 18 | return !callerAncestors.contains(ref.entry.getContainingClass()); | 22 | ClassEntry referencedClass = ref.entry.getContainingClass(); |
| 23 | |||
| 24 | if (!inheritanceIndex.getAncestors(contextClass).contains(referencedClass)) { | ||
| 25 | return true; // access to protected member not in superclass | ||
| 26 | } | ||
| 27 | |||
| 28 | if (ref.targetType.getKind() == ReferenceTargetType.Kind.NONE) { | ||
| 29 | return false; // access to superclass or static superclass member | ||
| 30 | } | ||
| 31 | |||
| 32 | // access to instance member only valid if target's class assignable to context class | ||
| 33 | return !(ref.targetType.getKind() == ReferenceTargetType.Kind.UNINITIALIZED || | ||
| 34 | ((ReferenceTargetType.ClassType) ref.targetType).getEntry().equals(contextClass) || | ||
| 35 | inheritanceIndex.getAncestors(((ReferenceTargetType.ClassType) ref.targetType).getEntry()).contains(contextClass)); | ||
| 19 | } | 36 | } |
| 20 | return !entryAcc.isPrivate(); // if isPrivate is false, it must be package-private | 37 | |
| 38 | return true; | ||
| 21 | } | 39 | } |
| 22 | 40 | ||
| 23 | private final HashMultimap<ClassEntry, ClassEntry> connections = HashMultimap.create(); | 41 | private final HashMultimap<ClassEntry, ClassEntry> connections = HashMultimap.create(); |
| @@ -25,8 +43,10 @@ public class PackageVisibilityIndex implements JarIndexer { | |||
| 25 | private final Map<ClassEntry, Set<ClassEntry>> classPartitions = Maps.newHashMap(); | 43 | private final Map<ClassEntry, Set<ClassEntry>> classPartitions = Maps.newHashMap(); |
| 26 | 44 | ||
| 27 | private void addConnection(ClassEntry classA, ClassEntry classB) { | 45 | private void addConnection(ClassEntry classA, ClassEntry classB) { |
| 28 | connections.put(classA, classB); | 46 | if (classA != classB) { |
| 29 | connections.put(classB, classA); | 47 | connections.put(classA, classB); |
| 48 | connections.put(classB, classA); | ||
| 49 | } | ||
| 30 | } | 50 | } |
| 31 | 51 | ||
| 32 | private void buildPartition(Set<ClassEntry> unassignedClasses, Set<ClassEntry> partition, ClassEntry member) { | 52 | private void buildPartition(Set<ClassEntry> unassignedClasses, Set<ClassEntry> partition, ClassEntry member) { |
diff --git a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java b/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java index f54c90d..b26b08b 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java | |||
| @@ -3,6 +3,7 @@ package cuchaz.enigma.analysis.index; | |||
| 3 | import com.google.common.collect.HashMultimap; | 3 | import com.google.common.collect.HashMultimap; |
| 4 | import com.google.common.collect.Multimap; | 4 | import com.google.common.collect.Multimap; |
| 5 | import cuchaz.enigma.analysis.EntryReference; | 5 | import cuchaz.enigma.analysis.EntryReference; |
| 6 | import cuchaz.enigma.analysis.ReferenceTargetType; | ||
| 6 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; | 7 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; |
| 7 | import cuchaz.enigma.translation.representation.Lambda; | 8 | import cuchaz.enigma.translation.representation.Lambda; |
| 8 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 9 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| @@ -57,27 +58,27 @@ public class ReferenceIndex implements JarIndexer { | |||
| 57 | } | 58 | } |
| 58 | 59 | ||
| 59 | @Override | 60 | @Override |
| 60 | public void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry) { | 61 | public void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry, ReferenceTargetType targetType) { |
| 61 | referencesToMethods.put(referencedEntry, new EntryReference<>(referencedEntry, referencedEntry.getName(), callerEntry)); | 62 | referencesToMethods.put(referencedEntry, new EntryReference<>(referencedEntry, referencedEntry.getName(), callerEntry, targetType)); |
| 62 | methodReferences.put(callerEntry, referencedEntry); | 63 | methodReferences.put(callerEntry, referencedEntry); |
| 63 | 64 | ||
| 64 | if (referencedEntry.isConstructor()) { | 65 | if (referencedEntry.isConstructor()) { |
| 65 | ClassEntry referencedClass = referencedEntry.getParent(); | 66 | ClassEntry referencedClass = referencedEntry.getParent(); |
| 66 | referencesToClasses.put(referencedClass, new EntryReference<>(referencedClass, referencedEntry.getName(), callerEntry)); | 67 | referencesToClasses.put(referencedClass, new EntryReference<>(referencedClass, referencedEntry.getName(), callerEntry, targetType)); |
| 67 | } | 68 | } |
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | @Override | 71 | @Override |
| 71 | public void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry) { | 72 | public void indexFieldReference(MethodDefEntry callerEntry, FieldEntry referencedEntry, ReferenceTargetType targetType) { |
| 72 | referencesToFields.put(referencedEntry, new EntryReference<>(referencedEntry, referencedEntry.getName(), callerEntry)); | 73 | referencesToFields.put(referencedEntry, new EntryReference<>(referencedEntry, referencedEntry.getName(), callerEntry, targetType)); |
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | @Override | 76 | @Override |
| 76 | public void indexLambda(MethodDefEntry callerEntry, Lambda lambda) { | 77 | public void indexLambda(MethodDefEntry callerEntry, Lambda lambda, ReferenceTargetType targetType) { |
| 77 | if (lambda.getImplMethod() instanceof MethodEntry) { | 78 | if (lambda.getImplMethod() instanceof MethodEntry) { |
| 78 | indexMethodReference(callerEntry, (MethodEntry) lambda.getImplMethod()); | 79 | indexMethodReference(callerEntry, (MethodEntry) lambda.getImplMethod(), targetType); |
| 79 | } else { | 80 | } else { |
| 80 | indexFieldReference(callerEntry, (FieldEntry) lambda.getImplMethod()); | 81 | indexFieldReference(callerEntry, (FieldEntry) lambda.getImplMethod(), targetType); |
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | indexMethodDescriptor(callerEntry, lambda.getInvokedType()); | 84 | indexMethodDescriptor(callerEntry, lambda.getInvokedType()); |