diff options
| author | 2019-05-15 12:45:41 +0200 | |
|---|---|---|
| committer | 2019-05-15 12:45:41 +0200 | |
| commit | df8def23dd0336d8a5d2369c5d4c0f4331838ef4 (patch) | |
| tree | de7fbdc9ccdf4a20c83103c0e2b0c3129c84430b /src/main | |
| parent | Resolve root when navigating to declaration (diff) | |
| download | enigma-fork-df8def23dd0336d8a5d2369c5d4c0f4331838ef4.tar.gz enigma-fork-df8def23dd0336d8a5d2369c5d4c0f4331838ef4.tar.xz enigma-fork-df8def23dd0336d8a5d2369c5d4c0f4331838ef4.zip | |
checkmappings command (#137)
* Use expected map sizes for remapped multimaps
* Index method and field types
* Add package visibility index
* Add checkmappings command and use System.err for error messages
* Use exit codes for errors
* Remove outer class check for package visible only refs
* Throw exception on mapping error instead of exiting
Diffstat (limited to 'src/main')
5 files changed, 247 insertions, 15 deletions
diff --git a/src/main/java/cuchaz/enigma/CommandMain.java b/src/main/java/cuchaz/enigma/CommandMain.java index c9f8382..db4fd12 100644 --- a/src/main/java/cuchaz/enigma/CommandMain.java +++ b/src/main/java/cuchaz/enigma/CommandMain.java | |||
| @@ -11,35 +11,47 @@ | |||
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.analysis.index.JarIndex; | ||
| 14 | import cuchaz.enigma.translation.mapping.EntryMapping; | 15 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 15 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | 16 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; |
| 16 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 17 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 18 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 17 | 19 | ||
| 18 | import java.io.File; | 20 | import java.io.File; |
| 19 | import java.nio.file.Files; | 21 | import java.nio.file.Files; |
| 20 | import java.nio.file.Path; | 22 | import java.nio.file.Path; |
| 21 | import java.nio.file.Paths; | 23 | import java.nio.file.Paths; |
| 22 | import java.util.Locale; | 24 | import java.util.Locale; |
| 25 | import java.util.Set; | ||
| 23 | import java.util.jar.JarFile; | 26 | import java.util.jar.JarFile; |
| 27 | import java.util.stream.Collectors; | ||
| 24 | 28 | ||
| 25 | public class CommandMain { | 29 | public class CommandMain { |
| 26 | 30 | ||
| 27 | public static void main(String[] args) throws Exception { | 31 | public static void main(String[] args) throws Exception { |
| 28 | try { | 32 | try { |
| 29 | // process the command | 33 | // process the command |
| 30 | String command = getArg(args, 0, "command", true); | 34 | String command = getArg(args, 0, "command", true).toLowerCase(Locale.ROOT); |
| 31 | if (command.equalsIgnoreCase("deobfuscate")) { | 35 | switch (command) { |
| 32 | deobfuscate(args); | 36 | case "deobfuscate": |
| 33 | } else if (command.equalsIgnoreCase("decompile")) { | 37 | deobfuscate(args); |
| 34 | decompile(args); | 38 | break; |
| 35 | } else if (command.equalsIgnoreCase("convertmappings")) { | 39 | case "decompile": |
| 36 | convertMappings(args); | 40 | decompile(args); |
| 37 | } else { | 41 | break; |
| 38 | throw new IllegalArgumentException("Command not recognized: " + command); | 42 | case "convertmappings": |
| 43 | convertMappings(args); | ||
| 44 | break; | ||
| 45 | case "checkmappings": | ||
| 46 | checkMappings(args); | ||
| 47 | break; | ||
| 48 | default: | ||
| 49 | throw new IllegalArgumentException("Command not recognized: " + command); | ||
| 39 | } | 50 | } |
| 40 | } catch (IllegalArgumentException ex) { | 51 | } catch (IllegalArgumentException ex) { |
| 41 | System.out.println(ex.getMessage()); | 52 | System.err.println(ex.getMessage()); |
| 42 | printHelp(); | 53 | printHelp(); |
| 54 | System.exit(1); | ||
| 43 | } | 55 | } |
| 44 | } | 56 | } |
| 45 | 57 | ||
| @@ -51,6 +63,7 @@ public class CommandMain { | |||
| 51 | System.out.println("\t\tdeobfuscate <in jar> <out jar> [<mappings file>]"); | 63 | System.out.println("\t\tdeobfuscate <in jar> <out jar> [<mappings file>]"); |
| 52 | System.out.println("\t\tdecompile <in jar> <out folder> [<mappings file>]"); | 64 | System.out.println("\t\tdecompile <in jar> <out folder> [<mappings file>]"); |
| 53 | System.out.println("\t\tconvertmappings <enigma mappings> <converted mappings> <ENIGMA_FILE|ENIGMA_DIRECTORY|SRG_FILE>"); | 65 | System.out.println("\t\tconvertmappings <enigma mappings> <converted mappings> <ENIGMA_FILE|ENIGMA_DIRECTORY|SRG_FILE>"); |
| 66 | System.out.println("\t\tcheckmappings <in jar> <mappings file>"); | ||
| 54 | } | 67 | } |
| 55 | 68 | ||
| 56 | private static void decompile(String[] args) throws Exception { | 69 | private static void decompile(String[] args) throws Exception { |
| @@ -100,6 +113,35 @@ public class CommandMain { | |||
| 100 | saveFormat.write(mappings, result.toPath(), new ConsoleProgressListener()); | 113 | saveFormat.write(mappings, result.toPath(), new ConsoleProgressListener()); |
| 101 | } | 114 | } |
| 102 | 115 | ||
| 116 | private static void checkMappings(String[] args) throws Exception { | ||
| 117 | File fileJarIn = getReadableFile(getArg(args, 1, "in jar", true)); | ||
| 118 | Path fileMappings = getReadablePath(getArg(args, 2, "enigma mapping", true)); | ||
| 119 | |||
| 120 | System.out.println("Reading JAR..."); | ||
| 121 | Deobfuscator deobfuscator = new Deobfuscator(new JarFile(fileJarIn)); | ||
| 122 | System.out.println("Reading mappings..."); | ||
| 123 | |||
| 124 | MappingFormat format = chooseEnigmaFormat(fileMappings); | ||
| 125 | EntryTree<EntryMapping> mappings = format.read(fileMappings, ProgressListener.VOID); | ||
| 126 | deobfuscator.setMappings(mappings); | ||
| 127 | |||
| 128 | JarIndex idx = deobfuscator.getJarIndex(); | ||
| 129 | |||
| 130 | boolean error = false; | ||
| 131 | |||
| 132 | for (Set<ClassEntry> partition : idx.getPackageVisibilityIndex().getPartitions()) { | ||
| 133 | long packages = partition.stream().map(deobfuscator.getMapper()::deobfuscate).map(ClassEntry::getPackageName).distinct().count(); | ||
| 134 | if (packages > 1) { | ||
| 135 | error = true; | ||
| 136 | System.err.println("ERROR: Must be in one package:\n" + partition.stream().map(deobfuscator.getMapper()::deobfuscate).map(ClassEntry::toString).sorted().collect(Collectors.joining("\n"))); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | if (error) { | ||
| 141 | throw new Exception("Access violations detected"); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 103 | private static MappingFormat chooseEnigmaFormat(Path path) { | 145 | private static MappingFormat chooseEnigmaFormat(Path path) { |
| 104 | if (Files.isDirectory(path)) { | 146 | if (Files.isDirectory(path)) { |
| 105 | return MappingFormat.ENIGMA_DIRECTORY; | 147 | return MappingFormat.ENIGMA_DIRECTORY; |
diff --git a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java b/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java index 773eaf1..31c6f54 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java | |||
| @@ -65,6 +65,11 @@ public class EntryIndex implements JarIndexer { | |||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | @Nullable | 67 | @Nullable |
| 68 | public AccessFlags getClassAccess(ClassEntry entry) { | ||
| 69 | return classes.get(entry); | ||
| 70 | } | ||
| 71 | |||
| 72 | @Nullable | ||
| 68 | public AccessFlags getEntryAccess(Entry<?> entry) { | 73 | public AccessFlags getEntryAccess(Entry<?> entry) { |
| 69 | if (entry instanceof MethodEntry) { | 74 | if (entry instanceof MethodEntry) { |
| 70 | return getMethodAccess((MethodEntry) entry); | 75 | return getMethodAccess((MethodEntry) entry); |
diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java index a429ff6..ac907af 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java | |||
| @@ -29,18 +29,20 @@ public class JarIndex implements JarIndexer { | |||
| 29 | private final InheritanceIndex inheritanceIndex; | 29 | private final InheritanceIndex inheritanceIndex; |
| 30 | private final ReferenceIndex referenceIndex; | 30 | private final ReferenceIndex referenceIndex; |
| 31 | private final BridgeMethodIndex bridgeMethodIndex; | 31 | private final BridgeMethodIndex bridgeMethodIndex; |
| 32 | private final PackageVisibilityIndex packageVisibilityIndex; | ||
| 32 | private final EntryResolver entryResolver; | 33 | private final EntryResolver entryResolver; |
| 33 | 34 | ||
| 34 | private final Collection<JarIndexer> indexers; | 35 | private final Collection<JarIndexer> indexers; |
| 35 | 36 | ||
| 36 | private final Multimap<String, MethodDefEntry> methodImplementations = HashMultimap.create(); | 37 | private final Multimap<String, MethodDefEntry> methodImplementations = HashMultimap.create(); |
| 37 | 38 | ||
| 38 | public JarIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex, BridgeMethodIndex bridgeMethodIndex) { | 39 | public JarIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex, BridgeMethodIndex bridgeMethodIndex, PackageVisibilityIndex packageVisibilityIndex) { |
| 39 | this.entryIndex = entryIndex; | 40 | this.entryIndex = entryIndex; |
| 40 | this.inheritanceIndex = inheritanceIndex; | 41 | this.inheritanceIndex = inheritanceIndex; |
| 41 | this.referenceIndex = referenceIndex; | 42 | this.referenceIndex = referenceIndex; |
| 42 | this.bridgeMethodIndex = bridgeMethodIndex; | 43 | this.bridgeMethodIndex = bridgeMethodIndex; |
| 43 | this.indexers = Arrays.asList(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex); | 44 | this.packageVisibilityIndex = packageVisibilityIndex; |
| 45 | this.indexers = Arrays.asList(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex); | ||
| 44 | this.entryResolver = new IndexEntryResolver(this); | 46 | this.entryResolver = new IndexEntryResolver(this); |
| 45 | } | 47 | } |
| 46 | 48 | ||
| @@ -49,7 +51,8 @@ public class JarIndex implements JarIndexer { | |||
| 49 | InheritanceIndex inheritanceIndex = new InheritanceIndex(entryIndex); | 51 | InheritanceIndex inheritanceIndex = new InheritanceIndex(entryIndex); |
| 50 | ReferenceIndex referenceIndex = new ReferenceIndex(); | 52 | ReferenceIndex referenceIndex = new ReferenceIndex(); |
| 51 | BridgeMethodIndex bridgeMethodIndex = new BridgeMethodIndex(entryIndex, inheritanceIndex, referenceIndex); | 53 | BridgeMethodIndex bridgeMethodIndex = new BridgeMethodIndex(entryIndex, inheritanceIndex, referenceIndex); |
| 52 | return new JarIndex(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex); | 54 | PackageVisibilityIndex packageVisibilityIndex = new PackageVisibilityIndex(); |
| 55 | return new JarIndex(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex); | ||
| 53 | } | 56 | } |
| 54 | 57 | ||
| 55 | public void indexJar(ParsedJar jar, Consumer<String> progress) { | 58 | public void indexJar(ParsedJar jar, Consumer<String> progress) { |
| @@ -142,6 +145,10 @@ public class JarIndex implements JarIndexer { | |||
| 142 | return bridgeMethodIndex; | 145 | return bridgeMethodIndex; |
| 143 | } | 146 | } |
| 144 | 147 | ||
| 148 | public PackageVisibilityIndex getPackageVisibilityIndex() { | ||
| 149 | return packageVisibilityIndex; | ||
| 150 | } | ||
| 151 | |||
| 145 | public EntryResolver getEntryResolver() { | 152 | public EntryResolver getEntryResolver() { |
| 146 | return entryResolver; | 153 | return entryResolver; |
| 147 | } | 154 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java b/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java new file mode 100644 index 0000000..9e9115f --- /dev/null +++ b/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | package cuchaz.enigma.analysis.index; | ||
| 2 | |||
| 3 | import com.google.common.collect.HashMultimap; | ||
| 4 | import com.google.common.collect.Lists; | ||
| 5 | import com.google.common.collect.Maps; | ||
| 6 | import com.google.common.collect.Sets; | ||
| 7 | import cuchaz.enigma.analysis.EntryReference; | ||
| 8 | import cuchaz.enigma.translation.representation.AccessFlags; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.*; | ||
| 10 | |||
| 11 | import java.util.*; | ||
| 12 | |||
| 13 | public class PackageVisibilityIndex implements JarIndexer { | ||
| 14 | private static boolean isPackageVisibleOnlyRef(AccessFlags entryAcc, EntryReference ref, InheritanceIndex inheritanceIndex) { | ||
| 15 | if (entryAcc.isPublic()) return false; | ||
| 16 | if (entryAcc.isProtected()) { | ||
| 17 | Set<ClassEntry> callerAncestors = inheritanceIndex.getAncestors(ref.context.getContainingClass()); | ||
| 18 | return !callerAncestors.contains(ref.entry.getContainingClass()); | ||
| 19 | } | ||
| 20 | return !entryAcc.isPrivate(); // if isPrivate is false, it must be package-private | ||
| 21 | } | ||
| 22 | |||
| 23 | private final HashMultimap<ClassEntry, ClassEntry> connections = HashMultimap.create(); | ||
| 24 | private final List<Set<ClassEntry>> partitions = Lists.newArrayList(); | ||
| 25 | private final Map<ClassEntry, Set<ClassEntry>> classPartitions = Maps.newHashMap(); | ||
| 26 | |||
| 27 | private void addConnection(ClassEntry classA, ClassEntry classB) { | ||
| 28 | connections.put(classA, classB); | ||
| 29 | connections.put(classB, classA); | ||
| 30 | } | ||
| 31 | |||
| 32 | private void buildPartition(Set<ClassEntry> unassignedClasses, Set<ClassEntry> partition, ClassEntry member) { | ||
| 33 | for (ClassEntry connected : connections.get(member)) { | ||
| 34 | if (unassignedClasses.remove(connected)) { | ||
| 35 | partition.add(connected); | ||
| 36 | buildPartition(unassignedClasses, partition, connected); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | private void addConnections(EntryIndex entryIndex, ReferenceIndex referenceIndex, InheritanceIndex inheritanceIndex) { | ||
| 42 | for (FieldEntry entry : entryIndex.getFields()) { | ||
| 43 | AccessFlags entryAcc = entryIndex.getFieldAccess(entry); | ||
| 44 | if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { | ||
| 45 | for (EntryReference<FieldEntry, MethodDefEntry> ref : referenceIndex.getReferencesToField(entry)) { | ||
| 46 | if (isPackageVisibleOnlyRef(entryAcc, ref, inheritanceIndex)) { | ||
| 47 | addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | for (MethodEntry entry : entryIndex.getMethods()) { | ||
| 54 | AccessFlags entryAcc = entryIndex.getMethodAccess(entry); | ||
| 55 | if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { | ||
| 56 | for (EntryReference<MethodEntry, MethodDefEntry> ref : referenceIndex.getReferencesToMethod(entry)) { | ||
| 57 | if (isPackageVisibleOnlyRef(entryAcc, ref, inheritanceIndex)) { | ||
| 58 | addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | for (ClassEntry entry : entryIndex.getClasses()) { | ||
| 65 | AccessFlags entryAcc = entryIndex.getClassAccess(entry); | ||
| 66 | if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { | ||
| 67 | for (EntryReference<ClassEntry, FieldDefEntry> ref : referenceIndex.getFieldTypeReferencesToClass(entry)) { | ||
| 68 | if (isPackageVisibleOnlyRef(entryAcc, ref, inheritanceIndex)) { | ||
| 69 | addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | for (EntryReference<ClassEntry, MethodDefEntry> ref : referenceIndex.getMethodTypeReferencesToClass(entry)) { | ||
| 74 | if (isPackageVisibleOnlyRef(entryAcc, ref, inheritanceIndex)) { | ||
| 75 | addConnection(ref.entry.getContainingClass(), ref.context.getContainingClass()); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | for (ClassEntry parent : inheritanceIndex.getParents(entry)) { | ||
| 81 | AccessFlags parentAcc = entryIndex.getClassAccess(parent); | ||
| 82 | if (parentAcc != null && !parentAcc.isPublic() && !parentAcc.isPrivate()) { | ||
| 83 | addConnection(entry, parent); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | ClassEntry outerClass = entry.getOuterClass(); | ||
| 88 | if (outerClass != null) { | ||
| 89 | addConnection(entry, outerClass); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | private void addPartitions(EntryIndex entryIndex) { | ||
| 95 | Set<ClassEntry> unassignedClasses = Sets.newHashSet(entryIndex.getClasses()); | ||
| 96 | while (!unassignedClasses.isEmpty()) { | ||
| 97 | Iterator<ClassEntry> iterator = unassignedClasses.iterator(); | ||
| 98 | ClassEntry initialEntry = iterator.next(); | ||
| 99 | iterator.remove(); | ||
| 100 | |||
| 101 | HashSet<ClassEntry> partition = Sets.newHashSet(); | ||
| 102 | partition.add(initialEntry); | ||
| 103 | buildPartition(unassignedClasses, partition, initialEntry); | ||
| 104 | partitions.add(partition); | ||
| 105 | for (ClassEntry entry : partition) { | ||
| 106 | classPartitions.put(entry, partition); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | public Collection<Set<ClassEntry>> getPartitions() { | ||
| 112 | return partitions; | ||
| 113 | } | ||
| 114 | |||
| 115 | public Set<ClassEntry> getPartition(ClassEntry classEntry) { | ||
| 116 | return classPartitions.get(classEntry); | ||
| 117 | } | ||
| 118 | |||
| 119 | @Override | ||
| 120 | public void processIndex(JarIndex index) { | ||
| 121 | EntryIndex entryIndex = index.getEntryIndex(); | ||
| 122 | ReferenceIndex referenceIndex = index.getReferenceIndex(); | ||
| 123 | InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); | ||
| 124 | addConnections(entryIndex, referenceIndex, inheritanceIndex); | ||
| 125 | addPartitions(entryIndex); | ||
| 126 | } | ||
| 127 | } | ||
diff --git a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java b/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java index 2b63c5d..6764ac0 100644 --- a/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java | |||
| @@ -4,6 +4,8 @@ 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.translation.mapping.ResolutionStrategy; | 6 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; |
| 7 | import cuchaz.enigma.translation.representation.MethodDescriptor; | ||
| 8 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 7 | import cuchaz.enigma.translation.representation.entry.*; | 9 | import cuchaz.enigma.translation.representation.entry.*; |
| 8 | 10 | ||
| 9 | import java.util.Collection; | 11 | import java.util.Collection; |
| @@ -15,6 +17,43 @@ public class ReferenceIndex implements JarIndexer { | |||
| 15 | private Multimap<MethodEntry, EntryReference<MethodEntry, MethodDefEntry>> referencesToMethods = HashMultimap.create(); | 17 | private Multimap<MethodEntry, EntryReference<MethodEntry, MethodDefEntry>> referencesToMethods = HashMultimap.create(); |
| 16 | private Multimap<ClassEntry, EntryReference<ClassEntry, MethodDefEntry>> referencesToClasses = HashMultimap.create(); | 18 | private Multimap<ClassEntry, EntryReference<ClassEntry, MethodDefEntry>> referencesToClasses = HashMultimap.create(); |
| 17 | private Multimap<FieldEntry, EntryReference<FieldEntry, MethodDefEntry>> referencesToFields = HashMultimap.create(); | 19 | private Multimap<FieldEntry, EntryReference<FieldEntry, MethodDefEntry>> referencesToFields = HashMultimap.create(); |
| 20 | private Multimap<ClassEntry, EntryReference<ClassEntry, FieldDefEntry>> fieldTypeReferences = HashMultimap.create(); | ||
| 21 | private Multimap<ClassEntry, EntryReference<ClassEntry, MethodDefEntry>> methodTypeReferences = HashMultimap.create(); | ||
| 22 | |||
| 23 | @Override | ||
| 24 | public void indexMethod(MethodDefEntry methodEntry) { | ||
| 25 | indexMethodDescriptor(methodEntry, methodEntry.getDesc()); | ||
| 26 | } | ||
| 27 | |||
| 28 | private void indexMethodDescriptor(MethodDefEntry entry, MethodDescriptor descriptor) { | ||
| 29 | for (TypeDescriptor typeDescriptor : descriptor.getArgumentDescs()) { | ||
| 30 | indexMethodTypeDescriptor(entry, typeDescriptor); | ||
| 31 | } | ||
| 32 | indexMethodTypeDescriptor(entry, descriptor.getReturnDesc()); | ||
| 33 | } | ||
| 34 | |||
| 35 | private void indexMethodTypeDescriptor(MethodDefEntry method, TypeDescriptor typeDescriptor) { | ||
| 36 | if (typeDescriptor.isType()) { | ||
| 37 | ClassEntry referencedClass = typeDescriptor.getTypeEntry(); | ||
| 38 | methodTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), method)); | ||
| 39 | } else if (typeDescriptor.isArray()) { | ||
| 40 | indexMethodTypeDescriptor(method, typeDescriptor.getArrayType()); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | @Override | ||
| 45 | public void indexField(FieldDefEntry fieldEntry) { | ||
| 46 | indexFieldTypeDescriptor(fieldEntry, fieldEntry.getDesc()); | ||
| 47 | } | ||
| 48 | |||
| 49 | private void indexFieldTypeDescriptor(FieldDefEntry field, TypeDescriptor typeDescriptor) { | ||
| 50 | if (typeDescriptor.isType()) { | ||
| 51 | ClassEntry referencedClass = typeDescriptor.getTypeEntry(); | ||
| 52 | fieldTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), field)); | ||
| 53 | } else if (typeDescriptor.isArray()) { | ||
| 54 | indexFieldTypeDescriptor(field, typeDescriptor.getArrayType()); | ||
| 55 | } | ||
| 56 | } | ||
| 18 | 57 | ||
| 19 | @Override | 58 | @Override |
| 20 | public void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry) { | 59 | public void indexMethodReference(MethodDefEntry callerEntry, MethodEntry referencedEntry) { |
| @@ -25,6 +64,8 @@ public class ReferenceIndex implements JarIndexer { | |||
| 25 | ClassEntry referencedClass = referencedEntry.getParent(); | 64 | ClassEntry referencedClass = referencedEntry.getParent(); |
| 26 | referencesToClasses.put(referencedClass, new EntryReference<>(referencedClass, referencedEntry.getName(), callerEntry)); | 65 | referencesToClasses.put(referencedClass, new EntryReference<>(referencedClass, referencedEntry.getName(), callerEntry)); |
| 27 | } | 66 | } |
| 67 | |||
| 68 | indexMethodDescriptor(callerEntry, referencedEntry.getDesc()); | ||
| 28 | } | 69 | } |
| 29 | 70 | ||
| 30 | @Override | 71 | @Override |
| @@ -38,10 +79,12 @@ public class ReferenceIndex implements JarIndexer { | |||
| 38 | referencesToMethods = remapReferencesTo(index, referencesToMethods); | 79 | referencesToMethods = remapReferencesTo(index, referencesToMethods); |
| 39 | referencesToClasses = remapReferencesTo(index, referencesToClasses); | 80 | referencesToClasses = remapReferencesTo(index, referencesToClasses); |
| 40 | referencesToFields = remapReferencesTo(index, referencesToFields); | 81 | referencesToFields = remapReferencesTo(index, referencesToFields); |
| 82 | fieldTypeReferences = remapReferencesTo(index, fieldTypeReferences); | ||
| 83 | methodTypeReferences = remapReferencesTo(index, methodTypeReferences); | ||
| 41 | } | 84 | } |
| 42 | 85 | ||
| 43 | private <K extends Entry<?>, V extends Entry<?>> Multimap<K, V> remapReferences(JarIndex index, Multimap<K, V> multimap) { | 86 | private <K extends Entry<?>, V extends Entry<?>> Multimap<K, V> remapReferences(JarIndex index, Multimap<K, V> multimap) { |
| 44 | Multimap<K, V> resolved = HashMultimap.create(); | 87 | Multimap<K, V> resolved = HashMultimap.create(multimap.keySet().size(), multimap.size() / multimap.keySet().size()); |
| 45 | for (Map.Entry<K, V> entry : multimap.entries()) { | 88 | for (Map.Entry<K, V> entry : multimap.entries()) { |
| 46 | resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); | 89 | resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); |
| 47 | } | 90 | } |
| @@ -49,7 +92,7 @@ public class ReferenceIndex implements JarIndexer { | |||
| 49 | } | 92 | } |
| 50 | 93 | ||
| 51 | private <E extends Entry<?>, C extends Entry<?>> Multimap<E, EntryReference<E, C>> remapReferencesTo(JarIndex index, Multimap<E, EntryReference<E, C>> multimap) { | 94 | private <E extends Entry<?>, C extends Entry<?>> Multimap<E, EntryReference<E, C>> remapReferencesTo(JarIndex index, Multimap<E, EntryReference<E, C>> multimap) { |
| 52 | Multimap<E, EntryReference<E, C>> resolved = HashMultimap.create(); | 95 | Multimap<E, EntryReference<E, C>> resolved = HashMultimap.create(multimap.keySet().size(), multimap.size() / multimap.keySet().size()); |
| 53 | for (Map.Entry<E, EntryReference<E, C>> entry : multimap.entries()) { | 96 | for (Map.Entry<E, EntryReference<E, C>> entry : multimap.entries()) { |
| 54 | resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); | 97 | resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); |
| 55 | } | 98 | } |
| @@ -79,4 +122,12 @@ public class ReferenceIndex implements JarIndexer { | |||
| 79 | public Collection<EntryReference<MethodEntry, MethodDefEntry>> getReferencesToMethod(MethodEntry entry) { | 122 | public Collection<EntryReference<MethodEntry, MethodDefEntry>> getReferencesToMethod(MethodEntry entry) { |
| 80 | return referencesToMethods.get(entry); | 123 | return referencesToMethods.get(entry); |
| 81 | } | 124 | } |
| 125 | |||
| 126 | public Collection<EntryReference<ClassEntry, FieldDefEntry>> getFieldTypeReferencesToClass(ClassEntry entry) { | ||
| 127 | return fieldTypeReferences.get(entry); | ||
| 128 | } | ||
| 129 | |||
| 130 | public Collection<EntryReference<ClassEntry, MethodDefEntry>> getMethodTypeReferencesToClass(ClassEntry entry) { | ||
| 131 | return methodTypeReferences.get(entry); | ||
| 132 | } | ||
| 82 | } | 133 | } |