1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
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<ClassEntry, ClassEntry> connections = HashMultimap.create();
private final List<Set<ClassEntry>> partitions = Lists.newArrayList();
private final Map<ClassEntry, Set<ClassEntry>> 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<ClassEntry> unassignedClasses, Set<ClassEntry> 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<FieldEntry, MethodDefEntry> 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<MethodEntry, MethodDefEntry> 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<ClassEntry, FieldDefEntry> ref : referenceIndex.getFieldTypeReferencesToClass(entry)) {
if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) {
addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass());
}
}
for (EntryReference<ClassEntry, MethodDefEntry> 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<ClassEntry> unassignedClasses = Sets.newHashSet(entryIndex.getClasses());
while (!unassignedClasses.isEmpty()) {
Iterator<ClassEntry> iterator = unassignedClasses.iterator();
ClassEntry initialEntry = iterator.next();
iterator.remove();
HashSet<ClassEntry> partition = Sets.newHashSet();
partition.add(initialEntry);
buildPartition(unassignedClasses, partition, initialEntry);
partitions.add(partition);
for (ClassEntry entry : partition) {
classPartitions.put(entry, partition);
}
}
}
public Collection<Set<ClassEntry>> getPartitions() {
return partitions;
}
public Set<ClassEntry> 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);
}
}
|