summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/analysis/index
diff options
context:
space:
mode:
authorGravatar Runemoro2019-11-02 17:23:14 -0400
committerGravatar modmuss502019-11-02 21:23:14 +0000
commit422b10b419eb010b612931e8b250b9dd1b7424ed (patch)
treeb9c1d3a7add5b8d01d5b0196d6c29ad00273987c /src/main/java/cuchaz/enigma/analysis/index
parentFix array class translation (#173) (diff)
downloadenigma-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')
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java6
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java156
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/JarIndex.java15
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java7
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java32
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java17
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 @@
1package cuchaz.enigma.analysis.index; 1package cuchaz.enigma.analysis.index;
2 2
3import cuchaz.enigma.analysis.IndexSimpleVerifier;
4import cuchaz.enigma.analysis.InterpreterPair;
5import cuchaz.enigma.analysis.MethodNodeWithAction;
6import cuchaz.enigma.analysis.ReferenceTargetType;
3import cuchaz.enigma.translation.representation.AccessFlags; 7import cuchaz.enigma.translation.representation.AccessFlags;
4import cuchaz.enigma.translation.representation.Lambda; 8import cuchaz.enigma.translation.representation.Lambda;
5import cuchaz.enigma.translation.representation.MethodDescriptor; 9import cuchaz.enigma.translation.representation.MethodDescriptor;
6import cuchaz.enigma.translation.representation.Signature; 10import cuchaz.enigma.translation.representation.Signature;
7import cuchaz.enigma.translation.representation.entry.*; 11import cuchaz.enigma.translation.representation.entry.*;
8import org.objectweb.asm.*; 12import org.objectweb.asm.*;
13import org.objectweb.asm.tree.AbstractInsnNode;
14import org.objectweb.asm.tree.FieldInsnNode;
15import org.objectweb.asm.tree.InvokeDynamicInsnNode;
16import org.objectweb.asm.tree.MethodInsnNode;
17import org.objectweb.asm.tree.analysis.*;
18
19import java.util.List;
20import java.util.stream.Collectors;
9 21
10public class IndexReferenceVisitor extends ClassVisitor { 22public 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;
15import com.google.common.collect.Multimap; 15import com.google.common.collect.Multimap;
16import cuchaz.enigma.ProgressListener; 16import cuchaz.enigma.ProgressListener;
17import cuchaz.enigma.analysis.ClassCache; 17import cuchaz.enigma.analysis.ClassCache;
18import cuchaz.enigma.analysis.ReferenceTargetType;
18import cuchaz.enigma.translation.mapping.EntryResolver; 19import cuchaz.enigma.translation.mapping.EntryResolver;
19import cuchaz.enigma.translation.mapping.IndexEntryResolver; 20import cuchaz.enigma.translation.mapping.IndexEntryResolver;
20import cuchaz.enigma.translation.representation.Lambda; 21import 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 @@
1package cuchaz.enigma.analysis.index; 1package cuchaz.enigma.analysis.index;
2 2
3import cuchaz.enigma.analysis.ReferenceTargetType;
3import cuchaz.enigma.translation.representation.Lambda; 4import cuchaz.enigma.translation.representation.Lambda;
4import cuchaz.enigma.translation.representation.entry.*; 5import 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;
5import com.google.common.collect.Maps; 5import com.google.common.collect.Maps;
6import com.google.common.collect.Sets; 6import com.google.common.collect.Sets;
7import cuchaz.enigma.analysis.EntryReference; 7import cuchaz.enigma.analysis.EntryReference;
8import cuchaz.enigma.analysis.ReferenceTargetType;
8import cuchaz.enigma.translation.representation.AccessFlags; 9import cuchaz.enigma.translation.representation.AccessFlags;
9import cuchaz.enigma.translation.representation.entry.*; 10import cuchaz.enigma.translation.representation.entry.*;
10 11
@@ -12,12 +13,29 @@ import java.util.*;
12 13
13public class PackageVisibilityIndex implements JarIndexer { 14public 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;
3import com.google.common.collect.HashMultimap; 3import com.google.common.collect.HashMultimap;
4import com.google.common.collect.Multimap; 4import com.google.common.collect.Multimap;
5import cuchaz.enigma.analysis.EntryReference; 5import cuchaz.enigma.analysis.EntryReference;
6import cuchaz.enigma.analysis.ReferenceTargetType;
6import cuchaz.enigma.translation.mapping.ResolutionStrategy; 7import cuchaz.enigma.translation.mapping.ResolutionStrategy;
7import cuchaz.enigma.translation.representation.Lambda; 8import cuchaz.enigma.translation.representation.Lambda;
8import cuchaz.enigma.translation.representation.MethodDescriptor; 9import 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());