diff options
| author | 2020-06-03 13:39:42 -0400 | |
|---|---|---|
| committer | 2020-06-03 18:39:42 +0100 | |
| commit | 0f47403d0220757fed189b76e2071e25b1025cb8 (patch) | |
| tree | 879bf72c4476f0a5e0d82da99d7ff2b2276bcaca /src/main/java/cuchaz/enigma/source/procyon | |
| parent | Fix search dialog hanging for a short time sometimes (#250) (diff) | |
| download | enigma-fork-0f47403d0220757fed189b76e2071e25b1025cb8.tar.gz enigma-fork-0f47403d0220757fed189b76e2071e25b1025cb8.tar.xz enigma-fork-0f47403d0220757fed189b76e2071e25b1025cb8.zip | |
Split GUI code to separate module (#242)
* Split into modules
* Post merge compile fixes
Co-authored-by: modmuss50 <modmuss50@gmail.com>
Diffstat (limited to 'src/main/java/cuchaz/enigma/source/procyon')
20 files changed, 0 insertions, 1837 deletions
diff --git a/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java b/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java deleted file mode 100644 index 2fae61a..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon; | ||
| 2 | |||
| 3 | import com.strobel.assembler.metadata.FieldDefinition; | ||
| 4 | import com.strobel.assembler.metadata.MethodDefinition; | ||
| 5 | import com.strobel.assembler.metadata.TypeDefinition; | ||
| 6 | import com.strobel.assembler.metadata.TypeReference; | ||
| 7 | import cuchaz.enigma.translation.representation.AccessFlags; | ||
| 8 | import cuchaz.enigma.translation.representation.MethodDescriptor; | ||
| 9 | import cuchaz.enigma.translation.representation.Signature; | ||
| 10 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 11 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | ||
| 12 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 13 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | ||
| 14 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 15 | |||
| 16 | public class EntryParser { | ||
| 17 | public static FieldDefEntry parse(FieldDefinition definition) { | ||
| 18 | ClassEntry owner = parse(definition.getDeclaringType()); | ||
| 19 | TypeDescriptor descriptor = new TypeDescriptor(definition.getErasedSignature()); | ||
| 20 | Signature signature = Signature.createTypedSignature(definition.getSignature()); | ||
| 21 | AccessFlags access = new AccessFlags(definition.getModifiers()); | ||
| 22 | return new FieldDefEntry(owner, definition.getName(), descriptor, signature, access, null); | ||
| 23 | } | ||
| 24 | |||
| 25 | public static ClassDefEntry parse(TypeDefinition def) { | ||
| 26 | String name = def.getInternalName(); | ||
| 27 | Signature signature = Signature.createSignature(def.getSignature()); | ||
| 28 | AccessFlags access = new AccessFlags(def.getModifiers()); | ||
| 29 | ClassEntry superClass = def.getBaseType() != null ? parse(def.getBaseType()) : null; | ||
| 30 | ClassEntry[] interfaces = def.getExplicitInterfaces().stream().map(EntryParser::parse).toArray(ClassEntry[]::new); | ||
| 31 | return new ClassDefEntry(name, signature, access, superClass, interfaces); | ||
| 32 | } | ||
| 33 | |||
| 34 | public static ClassEntry parse(TypeReference typeReference) { | ||
| 35 | return new ClassEntry(typeReference.getInternalName()); | ||
| 36 | } | ||
| 37 | |||
| 38 | public static MethodDefEntry parse(MethodDefinition definition) { | ||
| 39 | ClassEntry classEntry = parse(definition.getDeclaringType()); | ||
| 40 | MethodDescriptor descriptor = new MethodDescriptor(definition.getErasedSignature()); | ||
| 41 | Signature signature = Signature.createSignature(definition.getSignature()); | ||
| 42 | AccessFlags access = new AccessFlags(definition.getModifiers()); | ||
| 43 | return new MethodDefEntry(classEntry, definition.getName(), descriptor, signature, access, null); | ||
| 44 | } | ||
| 45 | |||
| 46 | public static TypeDescriptor parseTypeDescriptor(TypeReference type) { | ||
| 47 | return new TypeDescriptor(type.getErasedSignature()); | ||
| 48 | } | ||
| 49 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java b/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java deleted file mode 100644 index 37bc0c8..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java +++ /dev/null | |||
| @@ -1,81 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon; | ||
| 2 | |||
| 3 | import com.strobel.assembler.metadata.ITypeLoader; | ||
| 4 | import com.strobel.assembler.metadata.MetadataSystem; | ||
| 5 | import com.strobel.assembler.metadata.TypeDefinition; | ||
| 6 | import com.strobel.assembler.metadata.TypeReference; | ||
| 7 | import com.strobel.decompiler.DecompilerContext; | ||
| 8 | import com.strobel.decompiler.DecompilerSettings; | ||
| 9 | import com.strobel.decompiler.languages.java.BraceStyle; | ||
| 10 | import com.strobel.decompiler.languages.java.JavaFormattingOptions; | ||
| 11 | import com.strobel.decompiler.languages.java.ast.AstBuilder; | ||
| 12 | import com.strobel.decompiler.languages.java.ast.CompilationUnit; | ||
| 13 | import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; | ||
| 14 | import cuchaz.enigma.ClassProvider; | ||
| 15 | import cuchaz.enigma.api.EnigmaPluginContext; | ||
| 16 | import cuchaz.enigma.source.Source; | ||
| 17 | import cuchaz.enigma.source.Decompiler; | ||
| 18 | import cuchaz.enigma.source.SourceSettings; | ||
| 19 | import cuchaz.enigma.source.procyon.transformers.*; | ||
| 20 | import cuchaz.enigma.source.procyon.typeloader.CompiledSourceTypeLoader; | ||
| 21 | import cuchaz.enigma.source.procyon.typeloader.NoRetryMetadataSystem; | ||
| 22 | import cuchaz.enigma.source.procyon.typeloader.SynchronizedTypeLoader; | ||
| 23 | import cuchaz.enigma.utils.Utils; | ||
| 24 | |||
| 25 | public class ProcyonDecompiler implements Decompiler { | ||
| 26 | private final SourceSettings settings; | ||
| 27 | private final DecompilerSettings decompilerSettings; | ||
| 28 | private final MetadataSystem metadataSystem; | ||
| 29 | |||
| 30 | public ProcyonDecompiler(ClassProvider classProvider, SourceSettings settings) { | ||
| 31 | ITypeLoader typeLoader = new SynchronizedTypeLoader(new CompiledSourceTypeLoader(classProvider)); | ||
| 32 | |||
| 33 | metadataSystem = new NoRetryMetadataSystem(typeLoader); | ||
| 34 | metadataSystem.setEagerMethodLoadingEnabled(true); | ||
| 35 | |||
| 36 | decompilerSettings = DecompilerSettings.javaDefaults(); | ||
| 37 | decompilerSettings.setMergeVariables(Utils.getSystemPropertyAsBoolean("enigma.mergeVariables", true)); | ||
| 38 | decompilerSettings.setForceExplicitImports(Utils.getSystemPropertyAsBoolean("enigma.forceExplicitImports", true)); | ||
| 39 | decompilerSettings.setForceExplicitTypeArguments(Utils.getSystemPropertyAsBoolean("enigma.forceExplicitTypeArguments", true)); | ||
| 40 | decompilerSettings.setShowDebugLineNumbers(Utils.getSystemPropertyAsBoolean("enigma.showDebugLineNumbers", false)); | ||
| 41 | decompilerSettings.setShowSyntheticMembers(Utils.getSystemPropertyAsBoolean("enigma.showSyntheticMembers", false)); | ||
| 42 | decompilerSettings.setTypeLoader(typeLoader); | ||
| 43 | |||
| 44 | JavaFormattingOptions formattingOptions = decompilerSettings.getJavaFormattingOptions(); | ||
| 45 | formattingOptions.ClassBraceStyle = BraceStyle.EndOfLine; | ||
| 46 | formattingOptions.InterfaceBraceStyle = BraceStyle.EndOfLine; | ||
| 47 | formattingOptions.EnumBraceStyle = BraceStyle.EndOfLine; | ||
| 48 | |||
| 49 | this.settings = settings; | ||
| 50 | } | ||
| 51 | |||
| 52 | @Override | ||
| 53 | public Source getSource(String className) { | ||
| 54 | TypeReference type = metadataSystem.lookupType(className); | ||
| 55 | if (type == null) { | ||
| 56 | throw new Error(String.format("Unable to find desc: %s", className)); | ||
| 57 | } | ||
| 58 | |||
| 59 | TypeDefinition resolvedType = type.resolve(); | ||
| 60 | |||
| 61 | DecompilerContext context = new DecompilerContext(); | ||
| 62 | context.setCurrentType(resolvedType); | ||
| 63 | context.setSettings(decompilerSettings); | ||
| 64 | |||
| 65 | AstBuilder builder = new AstBuilder(context); | ||
| 66 | builder.addType(resolvedType); | ||
| 67 | builder.runTransformations(null); | ||
| 68 | CompilationUnit source = builder.getCompilationUnit(); | ||
| 69 | |||
| 70 | new ObfuscatedEnumSwitchRewriterTransform(context).run(source); | ||
| 71 | new VarargsFixer(context).run(source); | ||
| 72 | new RemoveObjectCasts(context).run(source); | ||
| 73 | new Java8Generics().run(source); | ||
| 74 | new InvalidIdentifierFix().run(source); | ||
| 75 | if (settings.removeImports) DropImportAstTransform.INSTANCE.run(source); | ||
| 76 | if (settings.removeVariableFinal) DropVarModifiersAstTransform.INSTANCE.run(source); | ||
| 77 | source.acceptVisitor(new InsertParenthesesVisitor(), null); | ||
| 78 | |||
| 79 | return new ProcyonSource(source, decompilerSettings); | ||
| 80 | } | ||
| 81 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java b/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java deleted file mode 100644 index 53c8c70..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon; | ||
| 2 | |||
| 3 | import com.strobel.decompiler.DecompilerSettings; | ||
| 4 | import com.strobel.decompiler.PlainTextOutput; | ||
| 5 | import com.strobel.decompiler.languages.java.JavaOutputVisitor; | ||
| 6 | import com.strobel.decompiler.languages.java.ast.CompilationUnit; | ||
| 7 | import cuchaz.enigma.source.Source; | ||
| 8 | import cuchaz.enigma.source.SourceIndex; | ||
| 9 | import cuchaz.enigma.source.procyon.index.SourceIndexVisitor; | ||
| 10 | import cuchaz.enigma.source.procyon.transformers.AddJavadocsAstTransform; | ||
| 11 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 12 | |||
| 13 | import java.io.StringWriter; | ||
| 14 | |||
| 15 | public class ProcyonSource implements Source { | ||
| 16 | private final DecompilerSettings settings; | ||
| 17 | private final CompilationUnit tree; | ||
| 18 | private String string; | ||
| 19 | |||
| 20 | public ProcyonSource(CompilationUnit tree, DecompilerSettings settings) { | ||
| 21 | this.settings = settings; | ||
| 22 | this.tree = tree; | ||
| 23 | } | ||
| 24 | |||
| 25 | @Override | ||
| 26 | public SourceIndex index() { | ||
| 27 | SourceIndex index = new SourceIndex(asString()); | ||
| 28 | tree.acceptVisitor(new SourceIndexVisitor(), index); | ||
| 29 | return index; | ||
| 30 | } | ||
| 31 | |||
| 32 | @Override | ||
| 33 | public String asString() { | ||
| 34 | if (string == null) { | ||
| 35 | StringWriter writer = new StringWriter(); | ||
| 36 | tree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(writer), settings), null); | ||
| 37 | string = writer.toString(); | ||
| 38 | } | ||
| 39 | |||
| 40 | return string; | ||
| 41 | } | ||
| 42 | |||
| 43 | @Override | ||
| 44 | public Source addJavadocs(EntryRemapper remapper) { | ||
| 45 | CompilationUnit remappedTree = (CompilationUnit) tree.clone(); | ||
| 46 | new AddJavadocsAstTransform(remapper).run(remappedTree); | ||
| 47 | return new ProcyonSource(remappedTree, settings); | ||
| 48 | } | ||
| 49 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java b/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java deleted file mode 100644 index f6eeb15..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java +++ /dev/null | |||
| @@ -1,95 +0,0 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2015 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Lesser General Public | ||
| 5 | * License v3.0 which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/lgpl.html | ||
| 7 | * <p> | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | |||
| 12 | package cuchaz.enigma.source.procyon.index; | ||
| 13 | |||
| 14 | import com.strobel.assembler.metadata.FieldDefinition; | ||
| 15 | import com.strobel.assembler.metadata.MethodDefinition; | ||
| 16 | import com.strobel.assembler.metadata.TypeDefinition; | ||
| 17 | import com.strobel.assembler.metadata.TypeReference; | ||
| 18 | import com.strobel.decompiler.languages.TextLocation; | ||
| 19 | import com.strobel.decompiler.languages.java.ast.*; | ||
| 20 | import cuchaz.enigma.source.SourceIndex; | ||
| 21 | import cuchaz.enigma.source.procyon.EntryParser; | ||
| 22 | import cuchaz.enigma.translation.representation.entry.*; | ||
| 23 | |||
| 24 | public class SourceIndexClassVisitor extends SourceIndexVisitor { | ||
| 25 | private ClassDefEntry classEntry; | ||
| 26 | |||
| 27 | public SourceIndexClassVisitor(ClassDefEntry classEntry) { | ||
| 28 | this.classEntry = classEntry; | ||
| 29 | } | ||
| 30 | |||
| 31 | @Override | ||
| 32 | public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { | ||
| 33 | // is this this class, or a subtype? | ||
| 34 | TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); | ||
| 35 | ClassDefEntry classEntry = EntryParser.parse(def); | ||
| 36 | if (!classEntry.equals(this.classEntry)) { | ||
| 37 | // it's a subtype, recurse | ||
| 38 | index.addDeclaration(TokenFactory.createToken(index, node.getNameToken()), classEntry); | ||
| 39 | return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); | ||
| 40 | } | ||
| 41 | |||
| 42 | return visitChildren(node, index); | ||
| 43 | } | ||
| 44 | |||
| 45 | @Override | ||
| 46 | public Void visitSimpleType(SimpleType node, SourceIndex index) { | ||
| 47 | TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); | ||
| 48 | if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { | ||
| 49 | ClassEntry classEntry = new ClassEntry(ref.getInternalName()); | ||
| 50 | index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), classEntry, this.classEntry); | ||
| 51 | } | ||
| 52 | |||
| 53 | return visitChildren(node, index); | ||
| 54 | } | ||
| 55 | |||
| 56 | @Override | ||
| 57 | public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { | ||
| 58 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); | ||
| 59 | MethodDefEntry methodEntry = EntryParser.parse(def); | ||
| 60 | AstNode tokenNode = node.getNameToken(); | ||
| 61 | if (methodEntry.isConstructor() && methodEntry.getName().equals("<clinit>")) { | ||
| 62 | // for static initializers, check elsewhere for the token node | ||
| 63 | tokenNode = node.getModifiers().firstOrNullObject(); | ||
| 64 | } | ||
| 65 | index.addDeclaration(TokenFactory.createToken(index, tokenNode), methodEntry); | ||
| 66 | return node.acceptVisitor(new SourceIndexMethodVisitor(methodEntry), index); | ||
| 67 | } | ||
| 68 | |||
| 69 | @Override | ||
| 70 | public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { | ||
| 71 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); | ||
| 72 | MethodDefEntry methodEntry = EntryParser.parse(def); | ||
| 73 | index.addDeclaration(TokenFactory.createToken(index, node.getNameToken()), methodEntry); | ||
| 74 | return node.acceptVisitor(new SourceIndexMethodVisitor(methodEntry), index); | ||
| 75 | } | ||
| 76 | |||
| 77 | @Override | ||
| 78 | public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { | ||
| 79 | FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); | ||
| 80 | FieldDefEntry fieldEntry = EntryParser.parse(def); | ||
| 81 | assert (node.getVariables().size() == 1); | ||
| 82 | VariableInitializer variable = node.getVariables().firstOrNullObject(); | ||
| 83 | index.addDeclaration(TokenFactory.createToken(index, variable.getNameToken()), fieldEntry); | ||
| 84 | return visitChildren(node, index); | ||
| 85 | } | ||
| 86 | |||
| 87 | @Override | ||
| 88 | public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { | ||
| 89 | // treat enum declarations as field declarations | ||
| 90 | FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); | ||
| 91 | FieldDefEntry fieldEntry = EntryParser.parse(def); | ||
| 92 | index.addDeclaration(TokenFactory.createToken(index, node.getNameToken()), fieldEntry); | ||
| 93 | return visitChildren(node, index); | ||
| 94 | } | ||
| 95 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java b/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java deleted file mode 100644 index 0e8bc51..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java +++ /dev/null | |||
| @@ -1,218 +0,0 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2015 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Lesser General Public | ||
| 5 | * License v3.0 which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/lgpl.html | ||
| 7 | * <p> | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | |||
| 12 | package cuchaz.enigma.source.procyon.index; | ||
| 13 | |||
| 14 | import com.google.common.collect.HashMultimap; | ||
| 15 | import com.google.common.collect.Multimap; | ||
| 16 | import com.strobel.assembler.metadata.*; | ||
| 17 | import com.strobel.decompiler.ast.Variable; | ||
| 18 | import com.strobel.decompiler.languages.TextLocation; | ||
| 19 | import com.strobel.decompiler.languages.java.ast.*; | ||
| 20 | import cuchaz.enigma.source.SourceIndex; | ||
| 21 | import cuchaz.enigma.source.procyon.EntryParser; | ||
| 22 | import cuchaz.enigma.translation.representation.MethodDescriptor; | ||
| 23 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 24 | import cuchaz.enigma.translation.representation.entry.*; | ||
| 25 | |||
| 26 | import java.lang.Error; | ||
| 27 | import java.util.HashMap; | ||
| 28 | import java.util.Map; | ||
| 29 | |||
| 30 | public class SourceIndexMethodVisitor extends SourceIndexVisitor { | ||
| 31 | private final MethodDefEntry methodEntry; | ||
| 32 | |||
| 33 | private Multimap<String, Identifier> unmatchedIdentifier = HashMultimap.create(); | ||
| 34 | private Map<String, Entry<?>> identifierEntryCache = new HashMap<>(); | ||
| 35 | |||
| 36 | public SourceIndexMethodVisitor(MethodDefEntry methodEntry) { | ||
| 37 | this.methodEntry = methodEntry; | ||
| 38 | } | ||
| 39 | |||
| 40 | @Override | ||
| 41 | public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { | ||
| 42 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | ||
| 43 | |||
| 44 | // get the behavior entry | ||
| 45 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | ||
| 46 | MethodEntry methodEntry = null; | ||
| 47 | if (ref instanceof MethodReference) { | ||
| 48 | methodEntry = new MethodEntry(classEntry, ref.getName(), new MethodDescriptor(ref.getErasedSignature())); | ||
| 49 | } | ||
| 50 | if (methodEntry != null) { | ||
| 51 | // get the node for the token | ||
| 52 | AstNode tokenNode = null; | ||
| 53 | if (node.getTarget() instanceof MemberReferenceExpression) { | ||
| 54 | tokenNode = ((MemberReferenceExpression) node.getTarget()).getMemberNameToken(); | ||
| 55 | } else if (node.getTarget() instanceof SuperReferenceExpression) { | ||
| 56 | tokenNode = node.getTarget(); | ||
| 57 | } else if (node.getTarget() instanceof ThisReferenceExpression) { | ||
| 58 | tokenNode = node.getTarget(); | ||
| 59 | } | ||
| 60 | if (tokenNode != null) { | ||
| 61 | index.addReference(TokenFactory.createToken(index, tokenNode), methodEntry, this.methodEntry); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | // Check for identifier | ||
| 66 | node.getArguments().stream().filter(expression -> expression instanceof IdentifierExpression) | ||
| 67 | .forEach(expression -> this.checkIdentifier((IdentifierExpression) expression, index)); | ||
| 68 | return visitChildren(node, index); | ||
| 69 | } | ||
| 70 | |||
| 71 | @Override | ||
| 72 | public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { | ||
| 73 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | ||
| 74 | if (ref instanceof FieldReference) { | ||
| 75 | // make sure this is actually a field | ||
| 76 | String erasedSignature = ref.getErasedSignature(); | ||
| 77 | if (erasedSignature.indexOf('(') >= 0) { | ||
| 78 | throw new Error("Expected a field here! got " + ref); | ||
| 79 | } | ||
| 80 | |||
| 81 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | ||
| 82 | FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new TypeDescriptor(erasedSignature)); | ||
| 83 | index.addReference(TokenFactory.createToken(index, node.getMemberNameToken()), fieldEntry, this.methodEntry); | ||
| 84 | } | ||
| 85 | |||
| 86 | return visitChildren(node, index); | ||
| 87 | } | ||
| 88 | |||
| 89 | @Override | ||
| 90 | public Void visitSimpleType(SimpleType node, SourceIndex index) { | ||
| 91 | TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); | ||
| 92 | if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { | ||
| 93 | ClassEntry classEntry = new ClassEntry(ref.getInternalName()); | ||
| 94 | index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), classEntry, this.methodEntry); | ||
| 95 | } | ||
| 96 | |||
| 97 | return visitChildren(node, index); | ||
| 98 | } | ||
| 99 | |||
| 100 | @Override | ||
| 101 | public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { | ||
| 102 | ParameterDefinition def = node.getUserData(Keys.PARAMETER_DEFINITION); | ||
| 103 | int parameterIndex = def.getSlot(); | ||
| 104 | |||
| 105 | if (parameterIndex >= 0) { | ||
| 106 | MethodDefEntry ownerMethod = methodEntry; | ||
| 107 | if (def.getMethod() instanceof MethodDefinition) { | ||
| 108 | ownerMethod = EntryParser.parse((MethodDefinition) def.getMethod()); | ||
| 109 | } | ||
| 110 | |||
| 111 | TypeDescriptor parameterType = EntryParser.parseTypeDescriptor(def.getParameterType()); | ||
| 112 | LocalVariableDefEntry localVariableEntry = new LocalVariableDefEntry(ownerMethod, parameterIndex, node.getName(), true, parameterType, null); | ||
| 113 | Identifier identifier = node.getNameToken(); | ||
| 114 | // cache the argument entry and the identifier | ||
| 115 | identifierEntryCache.put(identifier.getName(), localVariableEntry); | ||
| 116 | index.addDeclaration(TokenFactory.createToken(index, identifier), localVariableEntry); | ||
| 117 | } | ||
| 118 | |||
| 119 | return visitChildren(node, index); | ||
| 120 | } | ||
| 121 | |||
| 122 | @Override | ||
| 123 | public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { | ||
| 124 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | ||
| 125 | if (ref != null) { | ||
| 126 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | ||
| 127 | FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new TypeDescriptor(ref.getErasedSignature())); | ||
| 128 | index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), fieldEntry, this.methodEntry); | ||
| 129 | } else | ||
| 130 | this.checkIdentifier(node, index); | ||
| 131 | return visitChildren(node, index); | ||
| 132 | } | ||
| 133 | |||
| 134 | private void checkIdentifier(IdentifierExpression node, SourceIndex index) { | ||
| 135 | if (identifierEntryCache.containsKey(node.getIdentifier())) // If it's in the argument cache, create a token! | ||
| 136 | index.addDeclaration(TokenFactory.createToken(index, node.getIdentifierToken()), identifierEntryCache.get(node.getIdentifier())); | ||
| 137 | else | ||
| 138 | unmatchedIdentifier.put(node.getIdentifier(), node.getIdentifierToken()); // Not matched actually, put it! | ||
| 139 | } | ||
| 140 | |||
| 141 | private void addDeclarationToUnmatched(String key, SourceIndex index) { | ||
| 142 | Entry<?> entry = identifierEntryCache.get(key); | ||
| 143 | |||
| 144 | // This cannot happened in theory | ||
| 145 | if (entry == null) | ||
| 146 | return; | ||
| 147 | for (Identifier identifier : unmatchedIdentifier.get(key)) | ||
| 148 | index.addDeclaration(TokenFactory.createToken(index, identifier), entry); | ||
| 149 | unmatchedIdentifier.removeAll(key); | ||
| 150 | } | ||
| 151 | |||
| 152 | @Override | ||
| 153 | public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { | ||
| 154 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | ||
| 155 | if (ref != null && node.getType() instanceof SimpleType) { | ||
| 156 | SimpleType simpleTypeNode = (SimpleType) node.getType(); | ||
| 157 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | ||
| 158 | MethodEntry constructorEntry = new MethodEntry(classEntry, "<init>", new MethodDescriptor(ref.getErasedSignature())); | ||
| 159 | index.addReference(TokenFactory.createToken(index, simpleTypeNode.getIdentifierToken()), constructorEntry, this.methodEntry); | ||
| 160 | } | ||
| 161 | |||
| 162 | return visitChildren(node, index); | ||
| 163 | } | ||
| 164 | |||
| 165 | @Override | ||
| 166 | public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) { | ||
| 167 | AstNodeCollection<VariableInitializer> variables = node.getVariables(); | ||
| 168 | |||
| 169 | // Single assignation | ||
| 170 | if (variables.size() == 1) { | ||
| 171 | VariableInitializer initializer = variables.firstOrNullObject(); | ||
| 172 | if (initializer != null && node.getType() instanceof SimpleType) { | ||
| 173 | Identifier identifier = initializer.getNameToken(); | ||
| 174 | Variable variable = initializer.getUserData(Keys.VARIABLE); | ||
| 175 | if (variable != null) { | ||
| 176 | VariableDefinition originalVariable = variable.getOriginalVariable(); | ||
| 177 | if (originalVariable != null) { | ||
| 178 | int variableIndex = originalVariable.getSlot(); | ||
| 179 | if (variableIndex >= 0) { | ||
| 180 | MethodDefEntry ownerMethod = EntryParser.parse(originalVariable.getDeclaringMethod()); | ||
| 181 | TypeDescriptor variableType = EntryParser.parseTypeDescriptor(originalVariable.getVariableType()); | ||
| 182 | LocalVariableDefEntry localVariableEntry = new LocalVariableDefEntry(ownerMethod, variableIndex, initializer.getName(), false, variableType, null); | ||
| 183 | identifierEntryCache.put(identifier.getName(), localVariableEntry); | ||
| 184 | addDeclarationToUnmatched(identifier.getName(), index); | ||
| 185 | index.addDeclaration(TokenFactory.createToken(index, identifier), localVariableEntry); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | return visitChildren(node, index); | ||
| 192 | } | ||
| 193 | |||
| 194 | @Override | ||
| 195 | public Void visitMethodGroupExpression(MethodGroupExpression node, SourceIndex index) { | ||
| 196 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | ||
| 197 | |||
| 198 | if (ref instanceof MethodReference) { | ||
| 199 | // get the behavior entry | ||
| 200 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | ||
| 201 | MethodEntry methodEntry = new MethodEntry(classEntry, ref.getName(), new MethodDescriptor(ref.getErasedSignature())); | ||
| 202 | |||
| 203 | // get the node for the token | ||
| 204 | AstNode methodNameToken = node.getMethodNameToken(); | ||
| 205 | AstNode targetToken = node.getTarget(); | ||
| 206 | |||
| 207 | if (methodNameToken != null) { | ||
| 208 | index.addReference(TokenFactory.createToken(index, methodNameToken), methodEntry, this.methodEntry); | ||
| 209 | } | ||
| 210 | |||
| 211 | if (targetToken != null && !(targetToken instanceof ThisReferenceExpression)) { | ||
| 212 | index.addReference(TokenFactory.createToken(index, targetToken), methodEntry.getParent(), this.methodEntry); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | return visitChildren(node, index); | ||
| 217 | } | ||
| 218 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java b/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java deleted file mode 100644 index dad505f..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java +++ /dev/null | |||
| @@ -1,40 +0,0 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2015 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Lesser General Public | ||
| 5 | * License v3.0 which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/lgpl.html | ||
| 7 | * <p> | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | |||
| 12 | package cuchaz.enigma.source.procyon.index; | ||
| 13 | |||
| 14 | import com.strobel.assembler.metadata.TypeDefinition; | ||
| 15 | import com.strobel.decompiler.languages.java.ast.AstNode; | ||
| 16 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; | ||
| 17 | import com.strobel.decompiler.languages.java.ast.Keys; | ||
| 18 | import com.strobel.decompiler.languages.java.ast.TypeDeclaration; | ||
| 19 | import cuchaz.enigma.source.SourceIndex; | ||
| 20 | import cuchaz.enigma.source.procyon.EntryParser; | ||
| 21 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | ||
| 22 | |||
| 23 | public class SourceIndexVisitor extends DepthFirstAstVisitor<SourceIndex, Void> { | ||
| 24 | @Override | ||
| 25 | public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { | ||
| 26 | TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); | ||
| 27 | ClassDefEntry classEntry = EntryParser.parse(def); | ||
| 28 | index.addDeclaration(TokenFactory.createToken(index, node.getNameToken()), classEntry); | ||
| 29 | |||
| 30 | return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); | ||
| 31 | } | ||
| 32 | |||
| 33 | @Override | ||
| 34 | protected Void visitChildren(AstNode node, SourceIndex index) { | ||
| 35 | for (final AstNode child : node.getChildren()) { | ||
| 36 | child.acceptVisitor(this, index); | ||
| 37 | } | ||
| 38 | return null; | ||
| 39 | } | ||
| 40 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java b/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java deleted file mode 100644 index 62e7c10..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java +++ /dev/null | |||
| @@ -1,46 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.index; | ||
| 2 | |||
| 3 | import com.strobel.decompiler.languages.Region; | ||
| 4 | import com.strobel.decompiler.languages.java.ast.AstNode; | ||
| 5 | import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; | ||
| 6 | import com.strobel.decompiler.languages.java.ast.Identifier; | ||
| 7 | import com.strobel.decompiler.languages.java.ast.TypeDeclaration; | ||
| 8 | import cuchaz.enigma.analysis.Token; | ||
| 9 | import cuchaz.enigma.source.SourceIndex; | ||
| 10 | |||
| 11 | import java.util.regex.Pattern; | ||
| 12 | |||
| 13 | public class TokenFactory { | ||
| 14 | private static final Pattern ANONYMOUS_INNER = Pattern.compile("\\$\\d+$"); | ||
| 15 | |||
| 16 | public static Token createToken(SourceIndex index, AstNode node) { | ||
| 17 | String name = node instanceof Identifier ? ((Identifier) node).getName() : ""; | ||
| 18 | Region region = node.getRegion(); | ||
| 19 | |||
| 20 | if (region.getBeginLine() == 0) { | ||
| 21 | System.err.println("Got bad region from Procyon for node " + node); | ||
| 22 | return null; | ||
| 23 | } | ||
| 24 | |||
| 25 | int start = index.getPosition(region.getBeginLine(), region.getBeginColumn()); | ||
| 26 | int end = index.getPosition(region.getEndLine(), region.getEndColumn()); | ||
| 27 | String text = index.getSource().substring(start, end); | ||
| 28 | Token token = new Token(start, end, text); | ||
| 29 | |||
| 30 | boolean isAnonymousInner = | ||
| 31 | node instanceof Identifier && | ||
| 32 | name.indexOf('$') >= 0 && node.getParent() instanceof ConstructorDeclaration && | ||
| 33 | name.lastIndexOf('$') >= 0 && | ||
| 34 | !ANONYMOUS_INNER.matcher(name).matches(); | ||
| 35 | |||
| 36 | if (isAnonymousInner) { | ||
| 37 | TypeDeclaration type = node.getParent().getParent() instanceof TypeDeclaration ? (TypeDeclaration) node.getParent().getParent() : null; | ||
| 38 | if (type != null) { | ||
| 39 | name = type.getName(); | ||
| 40 | token.end = token.start + name.length(); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | return token; | ||
| 45 | } | ||
| 46 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java b/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java deleted file mode 100644 index 70fc8c6..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java +++ /dev/null | |||
| @@ -1,134 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | ||
| 2 | |||
| 3 | import com.google.common.base.Function; | ||
| 4 | import com.google.common.base.Strings; | ||
| 5 | import com.strobel.assembler.metadata.ParameterDefinition; | ||
| 6 | import com.strobel.decompiler.languages.java.ast.*; | ||
| 7 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | ||
| 8 | import cuchaz.enigma.source.procyon.EntryParser; | ||
| 9 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 10 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 11 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; | ||
| 12 | import cuchaz.enigma.translation.representation.entry.*; | ||
| 13 | |||
| 14 | import java.util.ArrayList; | ||
| 15 | import java.util.Collections; | ||
| 16 | import java.util.List; | ||
| 17 | import java.util.Objects; | ||
| 18 | import java.util.stream.Stream; | ||
| 19 | |||
| 20 | public final class AddJavadocsAstTransform implements IAstTransform { | ||
| 21 | |||
| 22 | private final EntryRemapper remapper; | ||
| 23 | |||
| 24 | public AddJavadocsAstTransform(EntryRemapper remapper) { | ||
| 25 | this.remapper = remapper; | ||
| 26 | } | ||
| 27 | |||
| 28 | @Override | ||
| 29 | public void run(AstNode compilationUnit) { | ||
| 30 | compilationUnit.acceptVisitor(new Visitor(remapper), null); | ||
| 31 | } | ||
| 32 | |||
| 33 | static class Visitor extends DepthFirstAstVisitor<Void, Void> { | ||
| 34 | |||
| 35 | private final EntryRemapper remapper; | ||
| 36 | |||
| 37 | Visitor(EntryRemapper remapper) { | ||
| 38 | this.remapper = remapper; | ||
| 39 | } | ||
| 40 | |||
| 41 | private <T extends AstNode> void addDoc(T node, Function<T, Entry<?>> retriever) { | ||
| 42 | final Comment[] comments = getComments(node, retriever); | ||
| 43 | if (comments != null) { | ||
| 44 | node.insertChildrenBefore(node.getFirstChild(), Roles.COMMENT, comments); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | private <T extends AstNode> Comment[] getComments(T node, Function<T, Entry<?>> retriever) { | ||
| 49 | final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node)); | ||
| 50 | final String docs = mapping == null ? null : Strings.emptyToNull(mapping.getJavadoc()); | ||
| 51 | return docs == null ? null : Stream.of(docs.split("\\R")).map(st -> new Comment(st, | ||
| 52 | CommentType.Documentation)).toArray(Comment[]::new); | ||
| 53 | } | ||
| 54 | |||
| 55 | private Comment[] getParameterComments(ParameterDeclaration node, Function<ParameterDeclaration, Entry<?>> retriever) { | ||
| 56 | final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node)); | ||
| 57 | final Comment[] ret = getComments(node, retriever); | ||
| 58 | if (ret != null) { | ||
| 59 | final String paramPrefix = "@param " + mapping.getTargetName() + " "; | ||
| 60 | final String indent = Strings.repeat(" ", paramPrefix.length()); | ||
| 61 | ret[0].setContent(paramPrefix + ret[0].getContent()); | ||
| 62 | for (int i = 1; i < ret.length; i++) { | ||
| 63 | ret[i].setContent(indent + ret[i].getContent()); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | return ret; | ||
| 67 | } | ||
| 68 | |||
| 69 | private void visitMethod(AstNode node) { | ||
| 70 | final MethodDefEntry methodDefEntry = EntryParser.parse(node.getUserData(Keys.METHOD_DEFINITION)); | ||
| 71 | final Comment[] baseComments = getComments(node, $ -> methodDefEntry); | ||
| 72 | List<Comment> comments = new ArrayList<>(); | ||
| 73 | if (baseComments != null) | ||
| 74 | Collections.addAll(comments, baseComments); | ||
| 75 | |||
| 76 | for (ParameterDeclaration dec : node.getChildrenByRole(Roles.PARAMETER)) { | ||
| 77 | ParameterDefinition def = dec.getUserData(Keys.PARAMETER_DEFINITION); | ||
| 78 | final Comment[] paramComments = getParameterComments(dec, $ -> new LocalVariableDefEntry(methodDefEntry, def.getSlot(), def.getName(), | ||
| 79 | true, | ||
| 80 | EntryParser.parseTypeDescriptor(def.getParameterType()), null)); | ||
| 81 | if (paramComments != null) | ||
| 82 | Collections.addAll(comments, paramComments); | ||
| 83 | } | ||
| 84 | |||
| 85 | if (!comments.isEmpty()) { | ||
| 86 | if (remapper.getObfResolver().resolveEntry(methodDefEntry, ResolutionStrategy.RESOLVE_ROOT).stream().noneMatch(e -> Objects.equals(e, methodDefEntry))) { | ||
| 87 | comments.add(0, new Comment("{@inheritDoc}", CommentType.Documentation)); | ||
| 88 | } | ||
| 89 | final AstNode oldFirst = node.getFirstChild(); | ||
| 90 | for (Comment comment : comments) { | ||
| 91 | node.insertChildBefore(oldFirst, comment, Roles.COMMENT); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | @Override | ||
| 97 | protected Void visitChildren(AstNode node, Void data) { | ||
| 98 | for (final AstNode child : node.getChildren()) { | ||
| 99 | child.acceptVisitor(this, data); | ||
| 100 | } | ||
| 101 | return null; | ||
| 102 | } | ||
| 103 | |||
| 104 | @Override | ||
| 105 | public Void visitMethodDeclaration(MethodDeclaration node, Void data) { | ||
| 106 | visitMethod(node); | ||
| 107 | return super.visitMethodDeclaration(node, data); | ||
| 108 | } | ||
| 109 | |||
| 110 | @Override | ||
| 111 | public Void visitConstructorDeclaration(ConstructorDeclaration node, Void data) { | ||
| 112 | visitMethod(node); | ||
| 113 | return super.visitConstructorDeclaration(node, data); | ||
| 114 | } | ||
| 115 | |||
| 116 | @Override | ||
| 117 | public Void visitFieldDeclaration(FieldDeclaration node, Void data) { | ||
| 118 | addDoc(node, dec -> EntryParser.parse(dec.getUserData(Keys.FIELD_DEFINITION))); | ||
| 119 | return super.visitFieldDeclaration(node, data); | ||
| 120 | } | ||
| 121 | |||
| 122 | @Override | ||
| 123 | public Void visitTypeDeclaration(TypeDeclaration node, Void data) { | ||
| 124 | addDoc(node, dec -> EntryParser.parse(dec.getUserData(Keys.TYPE_DEFINITION))); | ||
| 125 | return super.visitTypeDeclaration(node, data); | ||
| 126 | } | ||
| 127 | |||
| 128 | @Override | ||
| 129 | public Void visitEnumValueDeclaration(EnumValueDeclaration node, Void data) { | ||
| 130 | addDoc(node, dec -> EntryParser.parse(dec.getUserData(Keys.FIELD_DEFINITION))); | ||
| 131 | return super.visitEnumValueDeclaration(node, data); | ||
| 132 | } | ||
| 133 | } | ||
| 134 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/transformers/DropImportAstTransform.java b/src/main/java/cuchaz/enigma/source/procyon/transformers/DropImportAstTransform.java deleted file mode 100644 index 39e599d..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/transformers/DropImportAstTransform.java +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | ||
| 2 | |||
| 3 | import com.strobel.decompiler.languages.java.ast.AstNode; | ||
| 4 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; | ||
| 5 | import com.strobel.decompiler.languages.java.ast.ImportDeclaration; | ||
| 6 | import com.strobel.decompiler.languages.java.ast.PackageDeclaration; | ||
| 7 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | ||
| 8 | |||
| 9 | public final class DropImportAstTransform implements IAstTransform { | ||
| 10 | public static final DropImportAstTransform INSTANCE = new DropImportAstTransform(); | ||
| 11 | |||
| 12 | private DropImportAstTransform() { | ||
| 13 | } | ||
| 14 | |||
| 15 | @Override | ||
| 16 | public void run(AstNode compilationUnit) { | ||
| 17 | compilationUnit.acceptVisitor(new Visitor(), null); | ||
| 18 | } | ||
| 19 | |||
| 20 | static class Visitor extends DepthFirstAstVisitor<Void, Void> { | ||
| 21 | @Override | ||
| 22 | public Void visitPackageDeclaration(PackageDeclaration node, Void data) { | ||
| 23 | node.remove(); | ||
| 24 | return null; | ||
| 25 | } | ||
| 26 | |||
| 27 | @Override | ||
| 28 | public Void visitImportDeclaration(ImportDeclaration node, Void data) { | ||
| 29 | node.remove(); | ||
| 30 | return null; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java b/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java deleted file mode 100644 index b8c087b..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java +++ /dev/null | |||
| @@ -1,37 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | ||
| 2 | |||
| 3 | import com.strobel.decompiler.languages.java.ast.*; | ||
| 4 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | ||
| 5 | |||
| 6 | import javax.lang.model.element.Modifier; | ||
| 7 | |||
| 8 | public final class DropVarModifiersAstTransform implements IAstTransform { | ||
| 9 | public static final DropVarModifiersAstTransform INSTANCE = new DropVarModifiersAstTransform(); | ||
| 10 | |||
| 11 | private DropVarModifiersAstTransform() { | ||
| 12 | } | ||
| 13 | |||
| 14 | @Override | ||
| 15 | public void run(AstNode compilationUnit) { | ||
| 16 | compilationUnit.acceptVisitor(new Visitor(), null); | ||
| 17 | } | ||
| 18 | |||
| 19 | static class Visitor extends DepthFirstAstVisitor<Void, Void> { | ||
| 20 | @Override | ||
| 21 | public Void visitParameterDeclaration(ParameterDeclaration node, Void data) { | ||
| 22 | for (JavaModifierToken modifierToken : node.getChildrenByRole(EntityDeclaration.MODIFIER_ROLE)) { | ||
| 23 | if (modifierToken.getModifier() == Modifier.FINAL) { | ||
| 24 | modifierToken.remove(); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | return null; | ||
| 29 | } | ||
| 30 | |||
| 31 | @Override | ||
| 32 | public Void visitVariableDeclaration(VariableDeclarationStatement node, Void data) { | ||
| 33 | node.removeModifier(Modifier.FINAL); | ||
| 34 | return null; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java b/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java deleted file mode 100644 index 34d95fa..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | ||
| 2 | |||
| 3 | import com.strobel.decompiler.languages.java.ast.AstNode; | ||
| 4 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; | ||
| 5 | import com.strobel.decompiler.languages.java.ast.Identifier; | ||
| 6 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | ||
| 7 | |||
| 8 | /** | ||
| 9 | * Created by Thiakil on 13/07/2018. | ||
| 10 | */ | ||
| 11 | public class InvalidIdentifierFix implements IAstTransform { | ||
| 12 | @Override | ||
| 13 | public void run(AstNode compilationUnit) { | ||
| 14 | compilationUnit.acceptVisitor(new Visitor(), null); | ||
| 15 | } | ||
| 16 | |||
| 17 | class Visitor extends DepthFirstAstVisitor<Void,Void>{ | ||
| 18 | @Override | ||
| 19 | public Void visitIdentifier(Identifier node, Void data) { | ||
| 20 | super.visitIdentifier(node, data); | ||
| 21 | if (node.getName().equals("do") || node.getName().equals("if")){ | ||
| 22 | Identifier newIdentifier = Identifier.create(node.getName() + "_", node.getStartLocation()); | ||
| 23 | newIdentifier.copyUserDataFrom(node); | ||
| 24 | node.replaceWith(newIdentifier); | ||
| 25 | } | ||
| 26 | return null; | ||
| 27 | } | ||
| 28 | } | ||
| 29 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java b/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java deleted file mode 100644 index 8accfc7..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java +++ /dev/null | |||
| @@ -1,107 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | ||
| 2 | |||
| 3 | import com.strobel.assembler.metadata.BuiltinTypes; | ||
| 4 | import com.strobel.assembler.metadata.CommonTypeReferences; | ||
| 5 | import com.strobel.assembler.metadata.Flags; | ||
| 6 | import com.strobel.assembler.metadata.IGenericInstance; | ||
| 7 | import com.strobel.assembler.metadata.IMemberDefinition; | ||
| 8 | import com.strobel.assembler.metadata.JvmType; | ||
| 9 | import com.strobel.assembler.metadata.MemberReference; | ||
| 10 | import com.strobel.assembler.metadata.MethodDefinition; | ||
| 11 | import com.strobel.assembler.metadata.TypeDefinition; | ||
| 12 | import com.strobel.assembler.metadata.TypeReference; | ||
| 13 | import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; | ||
| 14 | import com.strobel.decompiler.languages.java.ast.AstNode; | ||
| 15 | import com.strobel.decompiler.languages.java.ast.AstNodeCollection; | ||
| 16 | import com.strobel.decompiler.languages.java.ast.AstType; | ||
| 17 | import com.strobel.decompiler.languages.java.ast.CastExpression; | ||
| 18 | import com.strobel.decompiler.languages.java.ast.ComposedType; | ||
| 19 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; | ||
| 20 | import com.strobel.decompiler.languages.java.ast.Expression; | ||
| 21 | import com.strobel.decompiler.languages.java.ast.Identifier; | ||
| 22 | import com.strobel.decompiler.languages.java.ast.InvocationExpression; | ||
| 23 | import com.strobel.decompiler.languages.java.ast.Keys; | ||
| 24 | import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; | ||
| 25 | import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; | ||
| 26 | import com.strobel.decompiler.languages.java.ast.Roles; | ||
| 27 | import com.strobel.decompiler.languages.java.ast.SimpleType; | ||
| 28 | import com.strobel.decompiler.languages.java.ast.WildcardType; | ||
| 29 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Created by Thiakil on 12/07/2018. | ||
| 33 | */ | ||
| 34 | public class Java8Generics implements IAstTransform { | ||
| 35 | |||
| 36 | @Override | ||
| 37 | public void run(AstNode compilationUnit) { | ||
| 38 | compilationUnit.acceptVisitor(new Visitor(), null); | ||
| 39 | } | ||
| 40 | |||
| 41 | static class Visitor extends DepthFirstAstVisitor<Void,Void>{ | ||
| 42 | |||
| 43 | @Override | ||
| 44 | public Void visitInvocationExpression(InvocationExpression node, Void data) { | ||
| 45 | super.visitInvocationExpression(node, data); | ||
| 46 | if (node.getTarget() instanceof MemberReferenceExpression){ | ||
| 47 | MemberReferenceExpression referenceExpression = (MemberReferenceExpression) node.getTarget(); | ||
| 48 | if (referenceExpression.getTypeArguments().stream().map(t->{ | ||
| 49 | TypeReference tr = t.toTypeReference(); | ||
| 50 | if (tr.getDeclaringType() != null){//ensure that inner types are resolved so we can get the TypeDefinition below | ||
| 51 | TypeReference resolved = tr.resolve(); | ||
| 52 | if (resolved != null) | ||
| 53 | return resolved; | ||
| 54 | } | ||
| 55 | return tr; | ||
| 56 | }).anyMatch(t -> t.isWildcardType() || (t instanceof TypeDefinition && ((TypeDefinition) t).isAnonymous()))) { | ||
| 57 | //these are invalid for invocations, let the compiler work it out | ||
| 58 | referenceExpression.getTypeArguments().clear(); | ||
| 59 | } else if (referenceExpression.getTypeArguments().stream().allMatch(t->t.toTypeReference().equals(CommonTypeReferences.Object))){ | ||
| 60 | //all are <Object>, thereby redundant and/or bad | ||
| 61 | referenceExpression.getTypeArguments().clear(); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | return null; | ||
| 65 | } | ||
| 66 | |||
| 67 | @Override | ||
| 68 | public Void visitObjectCreationExpression(ObjectCreationExpression node, Void data) { | ||
| 69 | super.visitObjectCreationExpression(node, data); | ||
| 70 | AstType type = node.getType(); | ||
| 71 | if (type instanceof SimpleType && !((SimpleType) type).getTypeArguments().isEmpty()){ | ||
| 72 | SimpleType simpleType = (SimpleType) type; | ||
| 73 | AstNodeCollection<AstType> typeArguments = simpleType.getTypeArguments(); | ||
| 74 | if (typeArguments.size() == 1 && typeArguments.firstOrNullObject().toTypeReference().equals(CommonTypeReferences.Object)){ | ||
| 75 | //all are <Object>, thereby redundant and/or bad | ||
| 76 | typeArguments.firstOrNullObject().getChildByRole(Roles.IDENTIFIER).replaceWith(Identifier.create("")); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | return null; | ||
| 80 | } | ||
| 81 | |||
| 82 | @Override | ||
| 83 | public Void visitCastExpression(CastExpression node, Void data) { | ||
| 84 | boolean doReplace = false; | ||
| 85 | TypeReference typeReference = node.getType().toTypeReference(); | ||
| 86 | if (typeReference.isArray() && typeReference.getElementType().isGenericType()){ | ||
| 87 | doReplace = true; | ||
| 88 | } else if (typeReference.isGenericType()) { | ||
| 89 | Expression target = node.getExpression(); | ||
| 90 | if (typeReference instanceof IGenericInstance && ((IGenericInstance)typeReference).getTypeArguments().stream().anyMatch(t->t.isWildcardType())){ | ||
| 91 | doReplace = true; | ||
| 92 | } else if (target instanceof InvocationExpression) { | ||
| 93 | InvocationExpression invocationExpression = (InvocationExpression)target; | ||
| 94 | if (invocationExpression.getTarget() instanceof MemberReferenceExpression && !((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().isEmpty()) { | ||
| 95 | ((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().clear(); | ||
| 96 | doReplace = true; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } | ||
| 100 | super.visitCastExpression(node, data); | ||
| 101 | if (doReplace){ | ||
| 102 | node.replaceWith(node.getExpression()); | ||
| 103 | } | ||
| 104 | return null; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java b/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java deleted file mode 100644 index 32bb72f..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java +++ /dev/null | |||
| @@ -1,414 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Originally: | ||
| 3 | * EnumSwitchRewriterTransform.java | ||
| 4 | * | ||
| 5 | * Copyright (c) 2013 Mike Strobel | ||
| 6 | * | ||
| 7 | * This source code is based on Mono.Cecil from Jb Evain, Copyright (c) Jb Evain; | ||
| 8 | * and ILSpy/ICSharpCode from SharpDevelop, Copyright (c) AlphaSierraPapa. | ||
| 9 | * | ||
| 10 | * This source code is subject to terms and conditions of the Apache License, Version 2.0. | ||
| 11 | * A copy of the license can be found in the License.html file at the root of this distribution. | ||
| 12 | * By using this source code in any fashion, you are agreeing to be bound by the terms of the | ||
| 13 | * Apache License, Version 2.0. | ||
| 14 | * | ||
| 15 | * You must not remove this notice, or any other, from this software. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package cuchaz.enigma.source.procyon.transformers; | ||
| 19 | |||
| 20 | import com.strobel.assembler.metadata.BuiltinTypes; | ||
| 21 | import com.strobel.assembler.metadata.FieldDefinition; | ||
| 22 | import com.strobel.assembler.metadata.MethodDefinition; | ||
| 23 | import com.strobel.assembler.metadata.TypeDefinition; | ||
| 24 | import com.strobel.assembler.metadata.TypeReference; | ||
| 25 | import com.strobel.core.SafeCloseable; | ||
| 26 | import com.strobel.core.VerifyArgument; | ||
| 27 | import com.strobel.decompiler.DecompilerContext; | ||
| 28 | import com.strobel.decompiler.languages.java.ast.AssignmentExpression; | ||
| 29 | import com.strobel.decompiler.languages.java.ast.AstBuilder; | ||
| 30 | import com.strobel.decompiler.languages.java.ast.AstNode; | ||
| 31 | import com.strobel.decompiler.languages.java.ast.CaseLabel; | ||
| 32 | import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor; | ||
| 33 | import com.strobel.decompiler.languages.java.ast.Expression; | ||
| 34 | import com.strobel.decompiler.languages.java.ast.IdentifierExpression; | ||
| 35 | import com.strobel.decompiler.languages.java.ast.IndexerExpression; | ||
| 36 | import com.strobel.decompiler.languages.java.ast.InvocationExpression; | ||
| 37 | import com.strobel.decompiler.languages.java.ast.Keys; | ||
| 38 | import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; | ||
| 39 | import com.strobel.decompiler.languages.java.ast.PrimitiveExpression; | ||
| 40 | import com.strobel.decompiler.languages.java.ast.SwitchSection; | ||
| 41 | import com.strobel.decompiler.languages.java.ast.SwitchStatement; | ||
| 42 | import com.strobel.decompiler.languages.java.ast.TypeDeclaration; | ||
| 43 | import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; | ||
| 44 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | ||
| 45 | |||
| 46 | import java.util.ArrayList; | ||
| 47 | import java.util.IdentityHashMap; | ||
| 48 | import java.util.LinkedHashMap; | ||
| 49 | import java.util.List; | ||
| 50 | import java.util.Map; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Copy of {@link com.strobel.decompiler.languages.java.ast.transforms.EnumSwitchRewriterTransform} modified to: | ||
| 54 | * - Not rely on a field containing "$SwitchMap$" (Proguard strips it) | ||
| 55 | * - Ignore classes *with* SwitchMap$ names (so the original can handle it) | ||
| 56 | * - Ignores inner synthetics that are not package private | ||
| 57 | */ | ||
| 58 | @SuppressWarnings("Duplicates") | ||
| 59 | public class ObfuscatedEnumSwitchRewriterTransform implements IAstTransform { | ||
| 60 | private final DecompilerContext _context; | ||
| 61 | |||
| 62 | public ObfuscatedEnumSwitchRewriterTransform(final DecompilerContext context) { | ||
| 63 | _context = VerifyArgument.notNull(context, "context"); | ||
| 64 | } | ||
| 65 | |||
| 66 | @Override | ||
| 67 | public void run(final AstNode compilationUnit) { | ||
| 68 | compilationUnit.acceptVisitor(new Visitor(_context), null); | ||
| 69 | } | ||
| 70 | |||
| 71 | private final static class Visitor extends ContextTrackingVisitor<Void> { | ||
| 72 | private final static class SwitchMapInfo { | ||
| 73 | final String enclosingType; | ||
| 74 | final Map<String, List<SwitchStatement>> switches = new LinkedHashMap<>(); | ||
| 75 | final Map<String, Map<Integer, Expression>> mappings = new LinkedHashMap<>(); | ||
| 76 | |||
| 77 | TypeDeclaration enclosingTypeDeclaration; | ||
| 78 | |||
| 79 | SwitchMapInfo(final String enclosingType) { | ||
| 80 | this.enclosingType = enclosingType; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | private final Map<String, SwitchMapInfo> _switchMaps = new LinkedHashMap<>(); | ||
| 85 | private boolean _isSwitchMapWrapper; | ||
| 86 | |||
| 87 | protected Visitor(final DecompilerContext context) { | ||
| 88 | super(context); | ||
| 89 | } | ||
| 90 | |||
| 91 | @Override | ||
| 92 | public Void visitTypeDeclaration(final TypeDeclaration typeDeclaration, final Void p) { | ||
| 93 | final boolean oldIsSwitchMapWrapper = _isSwitchMapWrapper; | ||
| 94 | final TypeDefinition typeDefinition = typeDeclaration.getUserData(Keys.TYPE_DEFINITION); | ||
| 95 | final boolean isSwitchMapWrapper = isSwitchMapWrapper(typeDefinition); | ||
| 96 | |||
| 97 | if (isSwitchMapWrapper) { | ||
| 98 | final String internalName = typeDefinition.getInternalName(); | ||
| 99 | |||
| 100 | SwitchMapInfo info = _switchMaps.get(internalName); | ||
| 101 | |||
| 102 | if (info == null) { | ||
| 103 | _switchMaps.put(internalName, info = new SwitchMapInfo(internalName)); | ||
| 104 | } | ||
| 105 | |||
| 106 | info.enclosingTypeDeclaration = typeDeclaration; | ||
| 107 | } | ||
| 108 | |||
| 109 | _isSwitchMapWrapper = isSwitchMapWrapper; | ||
| 110 | |||
| 111 | try { | ||
| 112 | super.visitTypeDeclaration(typeDeclaration, p); | ||
| 113 | } | ||
| 114 | finally { | ||
| 115 | _isSwitchMapWrapper = oldIsSwitchMapWrapper; | ||
| 116 | } | ||
| 117 | |||
| 118 | rewrite(); | ||
| 119 | |||
| 120 | return null; | ||
| 121 | } | ||
| 122 | |||
| 123 | @Override | ||
| 124 | public Void visitSwitchStatement(final SwitchStatement node, final Void data) { | ||
| 125 | final Expression test = node.getExpression(); | ||
| 126 | |||
| 127 | if (test instanceof IndexerExpression) { | ||
| 128 | final IndexerExpression indexer = (IndexerExpression) test; | ||
| 129 | final Expression array = indexer.getTarget(); | ||
| 130 | final Expression argument = indexer.getArgument(); | ||
| 131 | |||
| 132 | if (!(array instanceof MemberReferenceExpression)) { | ||
| 133 | return super.visitSwitchStatement(node, data); | ||
| 134 | } | ||
| 135 | |||
| 136 | final MemberReferenceExpression arrayAccess = (MemberReferenceExpression) array; | ||
| 137 | final Expression arrayOwner = arrayAccess.getTarget(); | ||
| 138 | final String mapName = arrayAccess.getMemberName(); | ||
| 139 | |||
| 140 | if (mapName == null || mapName.startsWith("$SwitchMap$") || !(arrayOwner instanceof TypeReferenceExpression)) { | ||
| 141 | return super.visitSwitchStatement(node, data); | ||
| 142 | } | ||
| 143 | |||
| 144 | final TypeReferenceExpression enclosingTypeExpression = (TypeReferenceExpression) arrayOwner; | ||
| 145 | final TypeReference enclosingType = enclosingTypeExpression.getType().getUserData(Keys.TYPE_REFERENCE); | ||
| 146 | |||
| 147 | if (!isSwitchMapWrapper(enclosingType) || !(argument instanceof InvocationExpression)) { | ||
| 148 | return super.visitSwitchStatement(node, data); | ||
| 149 | } | ||
| 150 | |||
| 151 | final InvocationExpression invocation = (InvocationExpression) argument; | ||
| 152 | final Expression invocationTarget = invocation.getTarget(); | ||
| 153 | |||
| 154 | if (!(invocationTarget instanceof MemberReferenceExpression)) { | ||
| 155 | return super.visitSwitchStatement(node, data); | ||
| 156 | } | ||
| 157 | |||
| 158 | final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget; | ||
| 159 | |||
| 160 | if (!"ordinal".equals(memberReference.getMemberName())) { | ||
| 161 | return super.visitSwitchStatement(node, data); | ||
| 162 | } | ||
| 163 | |||
| 164 | final String enclosingTypeName = enclosingType.getInternalName(); | ||
| 165 | |||
| 166 | SwitchMapInfo info = _switchMaps.get(enclosingTypeName); | ||
| 167 | |||
| 168 | if (info == null) { | ||
| 169 | _switchMaps.put(enclosingTypeName, info = new SwitchMapInfo(enclosingTypeName)); | ||
| 170 | |||
| 171 | final TypeDefinition resolvedType = enclosingType.resolve(); | ||
| 172 | |||
| 173 | if (resolvedType != null) { | ||
| 174 | AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER); | ||
| 175 | |||
| 176 | if (astBuilder == null) { | ||
| 177 | astBuilder = new AstBuilder(context); | ||
| 178 | } | ||
| 179 | |||
| 180 | try (final SafeCloseable importSuppression = astBuilder.suppressImports()) { | ||
| 181 | final TypeDeclaration declaration = astBuilder.createType(resolvedType); | ||
| 182 | |||
| 183 | declaration.acceptVisitor(this, data); | ||
| 184 | } | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | List<SwitchStatement> switches = info.switches.get(mapName); | ||
| 189 | |||
| 190 | if (switches == null) { | ||
| 191 | info.switches.put(mapName, switches = new ArrayList<>()); | ||
| 192 | } | ||
| 193 | |||
| 194 | switches.add(node); | ||
| 195 | } | ||
| 196 | |||
| 197 | return super.visitSwitchStatement(node, data); | ||
| 198 | } | ||
| 199 | |||
| 200 | @Override | ||
| 201 | public Void visitAssignmentExpression(final AssignmentExpression node, final Void data) { | ||
| 202 | final TypeDefinition currentType = context.getCurrentType(); | ||
| 203 | final MethodDefinition currentMethod = context.getCurrentMethod(); | ||
| 204 | |||
| 205 | if (_isSwitchMapWrapper && | ||
| 206 | currentType != null && | ||
| 207 | currentMethod != null && | ||
| 208 | currentMethod.isTypeInitializer()) { | ||
| 209 | |||
| 210 | final Expression left = node.getLeft(); | ||
| 211 | final Expression right = node.getRight(); | ||
| 212 | |||
| 213 | if (left instanceof IndexerExpression && | ||
| 214 | right instanceof PrimitiveExpression) { | ||
| 215 | |||
| 216 | String mapName = null; | ||
| 217 | |||
| 218 | final Expression array = ((IndexerExpression) left).getTarget(); | ||
| 219 | final Expression argument = ((IndexerExpression) left).getArgument(); | ||
| 220 | |||
| 221 | if (array instanceof MemberReferenceExpression) { | ||
| 222 | mapName = ((MemberReferenceExpression) array).getMemberName(); | ||
| 223 | } | ||
| 224 | else if (array instanceof IdentifierExpression) { | ||
| 225 | mapName = ((IdentifierExpression) array).getIdentifier(); | ||
| 226 | } | ||
| 227 | |||
| 228 | if (mapName == null || mapName.startsWith("$SwitchMap$")) { | ||
| 229 | return super.visitAssignmentExpression(node, data); | ||
| 230 | } | ||
| 231 | |||
| 232 | if (!(argument instanceof InvocationExpression)) { | ||
| 233 | return super.visitAssignmentExpression(node, data); | ||
| 234 | } | ||
| 235 | |||
| 236 | final InvocationExpression invocation = (InvocationExpression) argument; | ||
| 237 | final Expression invocationTarget = invocation.getTarget(); | ||
| 238 | |||
| 239 | if (!(invocationTarget instanceof MemberReferenceExpression)) { | ||
| 240 | return super.visitAssignmentExpression(node, data); | ||
| 241 | } | ||
| 242 | |||
| 243 | final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget; | ||
| 244 | final Expression memberTarget = memberReference.getTarget(); | ||
| 245 | |||
| 246 | if (!(memberTarget instanceof MemberReferenceExpression) || !"ordinal".equals(memberReference.getMemberName())) { | ||
| 247 | return super.visitAssignmentExpression(node, data); | ||
| 248 | } | ||
| 249 | |||
| 250 | final MemberReferenceExpression outerMemberReference = (MemberReferenceExpression) memberTarget; | ||
| 251 | final Expression outerMemberTarget = outerMemberReference.getTarget(); | ||
| 252 | |||
| 253 | if (!(outerMemberTarget instanceof TypeReferenceExpression)) { | ||
| 254 | return super.visitAssignmentExpression(node, data); | ||
| 255 | } | ||
| 256 | |||
| 257 | final String enclosingType = currentType.getInternalName(); | ||
| 258 | |||
| 259 | SwitchMapInfo info = _switchMaps.get(enclosingType); | ||
| 260 | |||
| 261 | if (info == null) { | ||
| 262 | _switchMaps.put(enclosingType, info = new SwitchMapInfo(enclosingType)); | ||
| 263 | |||
| 264 | AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER); | ||
| 265 | |||
| 266 | if (astBuilder == null) { | ||
| 267 | astBuilder = new AstBuilder(context); | ||
| 268 | } | ||
| 269 | |||
| 270 | info.enclosingTypeDeclaration = astBuilder.createType(currentType); | ||
| 271 | } | ||
| 272 | |||
| 273 | final PrimitiveExpression value = (PrimitiveExpression) right; | ||
| 274 | |||
| 275 | assert value.getValue() instanceof Integer; | ||
| 276 | |||
| 277 | Map<Integer, Expression> mapping = info.mappings.get(mapName); | ||
| 278 | |||
| 279 | if (mapping == null) { | ||
| 280 | info.mappings.put(mapName, mapping = new LinkedHashMap<>()); | ||
| 281 | } | ||
| 282 | |||
| 283 | final IdentifierExpression enumValue = new IdentifierExpression( Expression.MYSTERY_OFFSET, outerMemberReference.getMemberName()); | ||
| 284 | |||
| 285 | enumValue.putUserData(Keys.MEMBER_REFERENCE, outerMemberReference.getUserData(Keys.MEMBER_REFERENCE)); | ||
| 286 | |||
| 287 | mapping.put(((Number) value.getValue()).intValue(), enumValue); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | return super.visitAssignmentExpression(node, data); | ||
| 292 | } | ||
| 293 | |||
| 294 | private void rewrite() { | ||
| 295 | if (_switchMaps.isEmpty()) { | ||
| 296 | return; | ||
| 297 | } | ||
| 298 | |||
| 299 | for (final SwitchMapInfo info : _switchMaps.values()) { | ||
| 300 | rewrite(info); | ||
| 301 | } | ||
| 302 | |||
| 303 | // | ||
| 304 | // Remove switch map type wrappers that are no longer referenced. | ||
| 305 | // | ||
| 306 | |||
| 307 | outer: | ||
| 308 | for (final SwitchMapInfo info : _switchMaps.values()) { | ||
| 309 | for (final String mapName : info.switches.keySet()) { | ||
| 310 | final List<SwitchStatement> switches = info.switches.get(mapName); | ||
| 311 | |||
| 312 | if (switches != null && !switches.isEmpty()) { | ||
| 313 | continue outer; | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | final TypeDeclaration enclosingTypeDeclaration = info.enclosingTypeDeclaration; | ||
| 318 | |||
| 319 | if (enclosingTypeDeclaration != null) { | ||
| 320 | enclosingTypeDeclaration.remove(); | ||
| 321 | } | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | private void rewrite(final SwitchMapInfo info) { | ||
| 326 | if (info.switches.isEmpty()) { | ||
| 327 | return; | ||
| 328 | } | ||
| 329 | |||
| 330 | for (final String mapName : info.switches.keySet()) { | ||
| 331 | final List<SwitchStatement> switches = info.switches.get(mapName); | ||
| 332 | final Map<Integer, Expression> mappings = info.mappings.get(mapName); | ||
| 333 | |||
| 334 | if (switches != null && mappings != null) { | ||
| 335 | for (int i = 0; i < switches.size(); i++) { | ||
| 336 | if (rewriteSwitch(switches.get(i), mappings)) { | ||
| 337 | switches.remove(i--); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | } | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | private boolean rewriteSwitch(final SwitchStatement s, final Map<Integer, Expression> mappings) { | ||
| 345 | final Map<Expression, Expression> replacements = new IdentityHashMap<>(); | ||
| 346 | |||
| 347 | for (final SwitchSection section : s.getSwitchSections()) { | ||
| 348 | for (final CaseLabel caseLabel : section.getCaseLabels()) { | ||
| 349 | final Expression expression = caseLabel.getExpression(); | ||
| 350 | |||
| 351 | if (expression.isNull()) { | ||
| 352 | continue; | ||
| 353 | } | ||
| 354 | |||
| 355 | if (expression instanceof PrimitiveExpression) { | ||
| 356 | final Object value = ((PrimitiveExpression) expression).getValue(); | ||
| 357 | |||
| 358 | if (value instanceof Integer) { | ||
| 359 | final Expression replacement = mappings.get(value); | ||
| 360 | |||
| 361 | if (replacement != null) { | ||
| 362 | replacements.put(expression, replacement); | ||
| 363 | continue; | ||
| 364 | } | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | // | ||
| 369 | // If we can't rewrite all cases, we abort. | ||
| 370 | // | ||
| 371 | |||
| 372 | return false; | ||
| 373 | } | ||
| 374 | } | ||
| 375 | |||
| 376 | final IndexerExpression indexer = (IndexerExpression) s.getExpression(); | ||
| 377 | final InvocationExpression argument = (InvocationExpression) indexer.getArgument(); | ||
| 378 | final MemberReferenceExpression memberReference = (MemberReferenceExpression) argument.getTarget(); | ||
| 379 | final Expression newTest = memberReference.getTarget(); | ||
| 380 | |||
| 381 | newTest.remove(); | ||
| 382 | indexer.replaceWith(newTest); | ||
| 383 | |||
| 384 | for (final Map.Entry<Expression, Expression> entry : replacements.entrySet()) { | ||
| 385 | entry.getKey().replaceWith(entry.getValue().clone()); | ||
| 386 | } | ||
| 387 | |||
| 388 | return true; | ||
| 389 | } | ||
| 390 | |||
| 391 | private static boolean isSwitchMapWrapper(final TypeReference type) { | ||
| 392 | if (type == null) { | ||
| 393 | return false; | ||
| 394 | } | ||
| 395 | |||
| 396 | final TypeDefinition definition = type instanceof TypeDefinition ? (TypeDefinition) type | ||
| 397 | : type.resolve(); | ||
| 398 | |||
| 399 | if (definition == null || !definition.isSynthetic() || !definition.isInnerClass() || !definition.isPackagePrivate()) { | ||
| 400 | return false; | ||
| 401 | } | ||
| 402 | |||
| 403 | for (final FieldDefinition field : definition.getDeclaredFields()) { | ||
| 404 | if (!field.getName().startsWith("$SwitchMap$") && | ||
| 405 | BuiltinTypes.Integer.makeArrayType().equals(field.getFieldType())) { | ||
| 406 | |||
| 407 | return true; | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | return false; | ||
| 412 | } | ||
| 413 | } | ||
| 414 | } \ No newline at end of file | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java b/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java deleted file mode 100644 index cf0376f..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | ||
| 2 | |||
| 3 | import com.strobel.assembler.metadata.BuiltinTypes; | ||
| 4 | import com.strobel.decompiler.DecompilerContext; | ||
| 5 | import com.strobel.decompiler.languages.java.ast.AstNode; | ||
| 6 | import com.strobel.decompiler.languages.java.ast.CastExpression; | ||
| 7 | import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor; | ||
| 8 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | ||
| 9 | |||
| 10 | /** | ||
| 11 | * Created by Thiakil on 11/07/2018. | ||
| 12 | */ | ||
| 13 | public class RemoveObjectCasts implements IAstTransform { | ||
| 14 | private final DecompilerContext _context; | ||
| 15 | |||
| 16 | public RemoveObjectCasts(DecompilerContext context) { | ||
| 17 | _context = context; | ||
| 18 | } | ||
| 19 | |||
| 20 | @Override | ||
| 21 | public void run(AstNode compilationUnit) { | ||
| 22 | compilationUnit.acceptVisitor(new Visitor(_context), null); | ||
| 23 | } | ||
| 24 | |||
| 25 | private final static class Visitor extends ContextTrackingVisitor<Void>{ | ||
| 26 | |||
| 27 | protected Visitor(DecompilerContext context) { | ||
| 28 | super(context); | ||
| 29 | } | ||
| 30 | |||
| 31 | @Override | ||
| 32 | public Void visitCastExpression(CastExpression node, Void data) { | ||
| 33 | if (node.getType().toTypeReference().equals(BuiltinTypes.Object)){ | ||
| 34 | node.replaceWith(node.getExpression()); | ||
| 35 | } | ||
| 36 | return super.visitCastExpression(node, data); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java b/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java deleted file mode 100644 index d3ddaab..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java +++ /dev/null | |||
| @@ -1,197 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | ||
| 2 | |||
| 3 | import com.strobel.assembler.metadata.MemberReference; | ||
| 4 | import com.strobel.assembler.metadata.MetadataFilters; | ||
| 5 | import com.strobel.assembler.metadata.MetadataHelper; | ||
| 6 | import com.strobel.assembler.metadata.MethodBinder; | ||
| 7 | import com.strobel.assembler.metadata.MethodDefinition; | ||
| 8 | import com.strobel.assembler.metadata.MethodReference; | ||
| 9 | import com.strobel.assembler.metadata.TypeReference; | ||
| 10 | import com.strobel.core.StringUtilities; | ||
| 11 | import com.strobel.core.VerifyArgument; | ||
| 12 | import com.strobel.decompiler.DecompilerContext; | ||
| 13 | import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; | ||
| 14 | import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression; | ||
| 15 | import com.strobel.decompiler.languages.java.ast.AstNode; | ||
| 16 | import com.strobel.decompiler.languages.java.ast.AstNodeCollection; | ||
| 17 | import com.strobel.decompiler.languages.java.ast.CastExpression; | ||
| 18 | import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor; | ||
| 19 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; | ||
| 20 | import com.strobel.decompiler.languages.java.ast.Expression; | ||
| 21 | import com.strobel.decompiler.languages.java.ast.InvocationExpression; | ||
| 22 | import com.strobel.decompiler.languages.java.ast.JavaResolver; | ||
| 23 | import com.strobel.decompiler.languages.java.ast.Keys; | ||
| 24 | import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; | ||
| 25 | import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; | ||
| 26 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | ||
| 27 | import com.strobel.decompiler.semantics.ResolveResult; | ||
| 28 | |||
| 29 | import java.util.ArrayList; | ||
| 30 | import java.util.List; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * Created by Thiakil on 12/07/2018. | ||
| 34 | */ | ||
| 35 | public class VarargsFixer implements IAstTransform { | ||
| 36 | private final DecompilerContext _context; | ||
| 37 | |||
| 38 | public VarargsFixer(final DecompilerContext context) { | ||
| 39 | _context = VerifyArgument.notNull(context, "context"); | ||
| 40 | } | ||
| 41 | |||
| 42 | @Override | ||
| 43 | public void run(AstNode compilationUnit) { | ||
| 44 | compilationUnit.acceptVisitor(new Visitor(_context), null); | ||
| 45 | } | ||
| 46 | |||
| 47 | class Visitor extends ContextTrackingVisitor<Void> { | ||
| 48 | private final JavaResolver _resolver; | ||
| 49 | protected Visitor(DecompilerContext context) { | ||
| 50 | super(context); | ||
| 51 | _resolver = new JavaResolver(context); | ||
| 52 | } | ||
| 53 | |||
| 54 | //remove `new Object[0]` on varagrs as the normal tranformer doesnt do them | ||
| 55 | @Override | ||
| 56 | public Void visitInvocationExpression(InvocationExpression node, Void data) { | ||
| 57 | super.visitInvocationExpression(node, data); | ||
| 58 | MemberReference definition = node.getUserData(Keys.MEMBER_REFERENCE); | ||
| 59 | if (definition instanceof MethodDefinition && ((MethodDefinition) definition).isVarArgs()){ | ||
| 60 | AstNodeCollection<Expression> arguments = node.getArguments(); | ||
| 61 | Expression lastParam = arguments.lastOrNullObject(); | ||
| 62 | if (!lastParam.isNull() && lastParam instanceof ArrayCreationExpression){ | ||
| 63 | ArrayCreationExpression varargArray = (ArrayCreationExpression)lastParam; | ||
| 64 | if (varargArray.getInitializer().isNull() || varargArray.getInitializer().getElements().isEmpty()){ | ||
| 65 | lastParam.remove(); | ||
| 66 | } else { | ||
| 67 | for (Expression e : varargArray.getInitializer().getElements()){ | ||
| 68 | arguments.insertBefore(varargArray, e.clone()); | ||
| 69 | } | ||
| 70 | varargArray.remove(); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | return null; | ||
| 75 | } | ||
| 76 | |||
| 77 | //applies the vararg transform to object creation | ||
| 78 | @Override | ||
| 79 | public Void visitObjectCreationExpression(ObjectCreationExpression node, Void data) { | ||
| 80 | super.visitObjectCreationExpression(node, data); | ||
| 81 | final AstNodeCollection<Expression> arguments = node.getArguments(); | ||
| 82 | final Expression lastArgument = arguments.lastOrNullObject(); | ||
| 83 | |||
| 84 | Expression arrayArg = lastArgument; | ||
| 85 | |||
| 86 | if (arrayArg instanceof CastExpression) | ||
| 87 | arrayArg = ((CastExpression) arrayArg).getExpression(); | ||
| 88 | |||
| 89 | if (arrayArg == null || | ||
| 90 | arrayArg.isNull() || | ||
| 91 | !(arrayArg instanceof ArrayCreationExpression && | ||
| 92 | node.getTarget() instanceof MemberReferenceExpression)) { | ||
| 93 | |||
| 94 | return null; | ||
| 95 | } | ||
| 96 | |||
| 97 | final ArrayCreationExpression newArray = (ArrayCreationExpression) arrayArg; | ||
| 98 | final MemberReferenceExpression target = (MemberReferenceExpression) node.getTarget(); | ||
| 99 | |||
| 100 | if (!newArray.getAdditionalArraySpecifiers().hasSingleElement()) { | ||
| 101 | return null; | ||
| 102 | } | ||
| 103 | |||
| 104 | final MethodReference method = (MethodReference) node.getUserData(Keys.MEMBER_REFERENCE); | ||
| 105 | |||
| 106 | if (method == null) { | ||
| 107 | return null; | ||
| 108 | } | ||
| 109 | |||
| 110 | final MethodDefinition resolved = method.resolve(); | ||
| 111 | |||
| 112 | if (resolved == null || !resolved.isVarArgs()) { | ||
| 113 | return null; | ||
| 114 | } | ||
| 115 | |||
| 116 | final List<MethodReference> candidates; | ||
| 117 | final Expression invocationTarget = target.getTarget(); | ||
| 118 | |||
| 119 | if (invocationTarget == null || invocationTarget.isNull()) { | ||
| 120 | candidates = MetadataHelper.findMethods( | ||
| 121 | context.getCurrentType(), | ||
| 122 | MetadataFilters.matchName(resolved.getName()) | ||
| 123 | ); | ||
| 124 | } | ||
| 125 | else { | ||
| 126 | final ResolveResult targetResult = _resolver.apply(invocationTarget); | ||
| 127 | |||
| 128 | if (targetResult == null || targetResult.getType() == null) { | ||
| 129 | return null; | ||
| 130 | } | ||
| 131 | |||
| 132 | candidates = MetadataHelper.findMethods( | ||
| 133 | targetResult.getType(), | ||
| 134 | MetadataFilters.matchName(resolved.getName()) | ||
| 135 | ); | ||
| 136 | } | ||
| 137 | |||
| 138 | final List<TypeReference> argTypes = new ArrayList<>(); | ||
| 139 | |||
| 140 | for (final Expression argument : arguments) { | ||
| 141 | final ResolveResult argResult = _resolver.apply(argument); | ||
| 142 | |||
| 143 | if (argResult == null || argResult.getType() == null) { | ||
| 144 | return null; | ||
| 145 | } | ||
| 146 | |||
| 147 | argTypes.add(argResult.getType()); | ||
| 148 | } | ||
| 149 | |||
| 150 | final MethodBinder.BindResult c1 = MethodBinder.selectMethod(candidates, argTypes); | ||
| 151 | |||
| 152 | if (c1.isFailure() || c1.isAmbiguous()) { | ||
| 153 | return null; | ||
| 154 | } | ||
| 155 | |||
| 156 | argTypes.remove(argTypes.size() - 1); | ||
| 157 | |||
| 158 | final ArrayInitializerExpression initializer = newArray.getInitializer(); | ||
| 159 | final boolean hasElements = !initializer.isNull() && !initializer.getElements().isEmpty(); | ||
| 160 | |||
| 161 | if (hasElements) { | ||
| 162 | for (final Expression argument : initializer.getElements()) { | ||
| 163 | final ResolveResult argResult = _resolver.apply(argument); | ||
| 164 | |||
| 165 | if (argResult == null || argResult.getType() == null) { | ||
| 166 | return null; | ||
| 167 | } | ||
| 168 | |||
| 169 | argTypes.add(argResult.getType()); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | final MethodBinder.BindResult c2 = MethodBinder.selectMethod(candidates, argTypes); | ||
| 174 | |||
| 175 | if (c2.isFailure() || | ||
| 176 | c2.isAmbiguous() || | ||
| 177 | !StringUtilities.equals(c2.getMethod().getErasedSignature(), c1.getMethod().getErasedSignature())) { | ||
| 178 | |||
| 179 | return null; | ||
| 180 | } | ||
| 181 | |||
| 182 | lastArgument.remove(); | ||
| 183 | |||
| 184 | if (!hasElements) { | ||
| 185 | lastArgument.remove(); | ||
| 186 | return null; | ||
| 187 | } | ||
| 188 | |||
| 189 | for (final Expression newArg : initializer.getElements()) { | ||
| 190 | newArg.remove(); | ||
| 191 | arguments.add(newArg); | ||
| 192 | } | ||
| 193 | |||
| 194 | return null; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingClasspathTypeLoader.java b/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingClasspathTypeLoader.java deleted file mode 100644 index e702956..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingClasspathTypeLoader.java +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.typeloader; | ||
| 2 | |||
| 3 | import com.strobel.assembler.metadata.Buffer; | ||
| 4 | import com.strobel.assembler.metadata.ClasspathTypeLoader; | ||
| 5 | import com.strobel.assembler.metadata.ITypeLoader; | ||
| 6 | |||
| 7 | /** | ||
| 8 | * Caching version of {@link ClasspathTypeLoader} | ||
| 9 | */ | ||
| 10 | public class CachingClasspathTypeLoader extends CachingTypeLoader { | ||
| 11 | private static ITypeLoader extraClassPathLoader = null; | ||
| 12 | |||
| 13 | public static void setExtraClassPathLoader(ITypeLoader loader){ | ||
| 14 | extraClassPathLoader = loader; | ||
| 15 | } | ||
| 16 | |||
| 17 | private final ITypeLoader classpathLoader = new ClasspathTypeLoader(); | ||
| 18 | |||
| 19 | @Override | ||
| 20 | protected byte[] doLoad(String className) { | ||
| 21 | Buffer parentBuf = new Buffer(); | ||
| 22 | if (classpathLoader.tryLoadType(className, parentBuf)) { | ||
| 23 | return parentBuf.array(); | ||
| 24 | } | ||
| 25 | if (extraClassPathLoader != null){ | ||
| 26 | parentBuf.reset(); | ||
| 27 | if (extraClassPathLoader.tryLoadType(className, parentBuf)){ | ||
| 28 | return parentBuf.array(); | ||
| 29 | } | ||
| 30 | } | ||
| 31 | return EMPTY_ARRAY;//need to return *something* as null means no store | ||
| 32 | } | ||
| 33 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingTypeLoader.java b/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingTypeLoader.java deleted file mode 100644 index 5be5ddd..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingTypeLoader.java +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.typeloader; | ||
| 2 | |||
| 3 | import com.google.common.collect.Maps; | ||
| 4 | import com.strobel.assembler.metadata.Buffer; | ||
| 5 | import com.strobel.assembler.metadata.ITypeLoader; | ||
| 6 | |||
| 7 | import java.util.Map; | ||
| 8 | |||
| 9 | /** | ||
| 10 | * Common cache functions | ||
| 11 | */ | ||
| 12 | public abstract class CachingTypeLoader implements ITypeLoader { | ||
| 13 | protected static final byte[] EMPTY_ARRAY = {}; | ||
| 14 | |||
| 15 | private final Map<String, byte[]> cache = Maps.newHashMap(); | ||
| 16 | |||
| 17 | protected abstract byte[] doLoad(String className); | ||
| 18 | |||
| 19 | @Override | ||
| 20 | public boolean tryLoadType(String className, Buffer out) { | ||
| 21 | |||
| 22 | // check the cache | ||
| 23 | byte[] data = this.cache.computeIfAbsent(className, this::doLoad); | ||
| 24 | |||
| 25 | if (data == EMPTY_ARRAY) { | ||
| 26 | return false; | ||
| 27 | } | ||
| 28 | |||
| 29 | out.reset(data.length); | ||
| 30 | System.arraycopy(data, 0, out.array(), out.position(), data.length); | ||
| 31 | out.position(0); | ||
| 32 | return true; | ||
| 33 | } | ||
| 34 | |||
| 35 | public void clearCache() { | ||
| 36 | this.cache.clear(); | ||
| 37 | } | ||
| 38 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/typeloader/CompiledSourceTypeLoader.java b/src/main/java/cuchaz/enigma/source/procyon/typeloader/CompiledSourceTypeLoader.java deleted file mode 100644 index e703d3b..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/typeloader/CompiledSourceTypeLoader.java +++ /dev/null | |||
| @@ -1,140 +0,0 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2015 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Lesser General Public | ||
| 5 | * License v3.0 which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/lgpl.html | ||
| 7 | * <p> | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | |||
| 12 | package cuchaz.enigma.source.procyon.typeloader; | ||
| 13 | |||
| 14 | import com.google.common.collect.Lists; | ||
| 15 | import com.strobel.assembler.metadata.Buffer; | ||
| 16 | import com.strobel.assembler.metadata.ITypeLoader; | ||
| 17 | import cuchaz.enigma.ClassProvider; | ||
| 18 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 19 | import org.objectweb.asm.ClassVisitor; | ||
| 20 | import org.objectweb.asm.ClassWriter; | ||
| 21 | import org.objectweb.asm.Opcodes; | ||
| 22 | import org.objectweb.asm.tree.AbstractInsnNode; | ||
| 23 | import org.objectweb.asm.tree.ClassNode; | ||
| 24 | import org.objectweb.asm.tree.MethodInsnNode; | ||
| 25 | import org.objectweb.asm.tree.MethodNode; | ||
| 26 | |||
| 27 | import java.util.Collection; | ||
| 28 | import java.util.LinkedList; | ||
| 29 | import java.util.List; | ||
| 30 | import java.util.function.Function; | ||
| 31 | |||
| 32 | public class CompiledSourceTypeLoader extends CachingTypeLoader { | ||
| 33 | //Store one instance as the classpath shouldn't change during load | ||
| 34 | private static final ITypeLoader CLASSPATH_TYPE_LOADER = new CachingClasspathTypeLoader(); | ||
| 35 | |||
| 36 | private final ClassProvider compiledSource; | ||
| 37 | private final LinkedList<Function<ClassVisitor, ClassVisitor>> visitors = new LinkedList<>(); | ||
| 38 | |||
| 39 | public CompiledSourceTypeLoader(ClassProvider compiledSource) { | ||
| 40 | this.compiledSource = compiledSource; | ||
| 41 | } | ||
| 42 | |||
| 43 | public void addVisitor(Function<ClassVisitor, ClassVisitor> visitor) { | ||
| 44 | this.visitors.addFirst(visitor); | ||
| 45 | } | ||
| 46 | |||
| 47 | @Override | ||
| 48 | protected byte[] doLoad(String className) { | ||
| 49 | byte[] data = loadType(className); | ||
| 50 | if (data == null) { | ||
| 51 | return loadClasspath(className); | ||
| 52 | } | ||
| 53 | |||
| 54 | return data; | ||
| 55 | } | ||
| 56 | |||
| 57 | private byte[] loadClasspath(String name) { | ||
| 58 | Buffer parentBuf = new Buffer(); | ||
| 59 | if (CLASSPATH_TYPE_LOADER.tryLoadType(name, parentBuf)) { | ||
| 60 | return parentBuf.array(); | ||
| 61 | } | ||
| 62 | return EMPTY_ARRAY; | ||
| 63 | } | ||
| 64 | |||
| 65 | private byte[] loadType(String className) { | ||
| 66 | ClassEntry entry = new ClassEntry(className); | ||
| 67 | |||
| 68 | // find the class in the jar | ||
| 69 | ClassNode node = findClassNode(entry); | ||
| 70 | if (node == null) { | ||
| 71 | // couldn't find it | ||
| 72 | return null; | ||
| 73 | } | ||
| 74 | |||
| 75 | removeRedundantClassCalls(node); | ||
| 76 | |||
| 77 | ClassWriter writer = new ClassWriter(0); | ||
| 78 | |||
| 79 | ClassVisitor visitor = writer; | ||
| 80 | for (Function<ClassVisitor, ClassVisitor> visitorFunction : this.visitors) { | ||
| 81 | visitor = visitorFunction.apply(visitor); | ||
| 82 | } | ||
| 83 | |||
| 84 | node.accept(visitor); | ||
| 85 | |||
| 86 | // we have a transformed class! | ||
| 87 | return writer.toByteArray(); | ||
| 88 | } | ||
| 89 | |||
| 90 | private void removeRedundantClassCalls(ClassNode node) { | ||
| 91 | // remove <obj>.getClass() calls that are seemingly injected | ||
| 92 | // DUP | ||
| 93 | // INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class; | ||
| 94 | // POP | ||
| 95 | for (MethodNode methodNode : node.methods) { | ||
| 96 | AbstractInsnNode insnNode = methodNode.instructions.getFirst(); | ||
| 97 | while (insnNode != null) { | ||
| 98 | if (insnNode instanceof MethodInsnNode && insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) { | ||
| 99 | MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; | ||
| 100 | if (methodInsnNode.name.equals("getClass") && methodInsnNode.owner.equals("java/lang/Object") && methodInsnNode.desc.equals("()Ljava/lang/Class;")) { | ||
| 101 | AbstractInsnNode previous = methodInsnNode.getPrevious(); | ||
| 102 | AbstractInsnNode next = methodInsnNode.getNext(); | ||
| 103 | if (previous.getOpcode() == Opcodes.DUP && next.getOpcode() == Opcodes.POP) { | ||
| 104 | insnNode = previous.getPrevious();//reset the iterator so it gets the new next instruction | ||
| 105 | methodNode.instructions.remove(previous); | ||
| 106 | methodNode.instructions.remove(methodInsnNode); | ||
| 107 | methodNode.instructions.remove(next); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | } | ||
| 111 | insnNode = insnNode.getNext(); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | private ClassNode findClassNode(ClassEntry entry) { | ||
| 117 | // try to find the class in the jar | ||
| 118 | for (String className : getClassNamesToTry(entry)) { | ||
| 119 | ClassNode node = compiledSource.getClassNode(className); | ||
| 120 | if (node != null) { | ||
| 121 | return node; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | // didn't find it ;_; | ||
| 126 | return null; | ||
| 127 | } | ||
| 128 | |||
| 129 | private Collection<String> getClassNamesToTry(ClassEntry entry) { | ||
| 130 | List<String> classNamesToTry = Lists.newArrayList(); | ||
| 131 | classNamesToTry.add(entry.getFullName()); | ||
| 132 | |||
| 133 | ClassEntry outerClass = entry.getOuterClass(); | ||
| 134 | if (outerClass != null) { | ||
| 135 | classNamesToTry.addAll(getClassNamesToTry(outerClass)); | ||
| 136 | } | ||
| 137 | |||
| 138 | return classNamesToTry; | ||
| 139 | } | ||
| 140 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/typeloader/NoRetryMetadataSystem.java b/src/main/java/cuchaz/enigma/source/procyon/typeloader/NoRetryMetadataSystem.java deleted file mode 100644 index c4732b0..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/typeloader/NoRetryMetadataSystem.java +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.typeloader; | ||
| 2 | |||
| 3 | import com.strobel.assembler.metadata.ITypeLoader; | ||
| 4 | import com.strobel.assembler.metadata.MetadataSystem; | ||
| 5 | import com.strobel.assembler.metadata.TypeDefinition; | ||
| 6 | import com.strobel.assembler.metadata.TypeReference; | ||
| 7 | |||
| 8 | import java.util.Collections; | ||
| 9 | import java.util.Set; | ||
| 10 | import java.util.concurrent.ConcurrentHashMap; | ||
| 11 | |||
| 12 | public final class NoRetryMetadataSystem extends MetadataSystem { | ||
| 13 | private final Set<String> failedTypes = Collections.newSetFromMap(new ConcurrentHashMap<>()); | ||
| 14 | |||
| 15 | public NoRetryMetadataSystem(final ITypeLoader typeLoader) { | ||
| 16 | super(typeLoader); | ||
| 17 | } | ||
| 18 | |||
| 19 | @Override | ||
| 20 | protected synchronized TypeDefinition resolveType(final String descriptor, final boolean mightBePrimitive) { | ||
| 21 | if (failedTypes.contains(descriptor)) { | ||
| 22 | return null; | ||
| 23 | } | ||
| 24 | |||
| 25 | final TypeDefinition result = super.resolveType(descriptor, mightBePrimitive); | ||
| 26 | |||
| 27 | if (result == null) { | ||
| 28 | failedTypes.add(descriptor); | ||
| 29 | } | ||
| 30 | |||
| 31 | return result; | ||
| 32 | } | ||
| 33 | |||
| 34 | @Override | ||
| 35 | public synchronized TypeDefinition resolve(final TypeReference type) { | ||
| 36 | return super.resolve(type); | ||
| 37 | } | ||
| 38 | } | ||
diff --git a/src/main/java/cuchaz/enigma/source/procyon/typeloader/SynchronizedTypeLoader.java b/src/main/java/cuchaz/enigma/source/procyon/typeloader/SynchronizedTypeLoader.java deleted file mode 100644 index 86c6ecc..0000000 --- a/src/main/java/cuchaz/enigma/source/procyon/typeloader/SynchronizedTypeLoader.java +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.typeloader; | ||
| 2 | |||
| 3 | import com.strobel.assembler.metadata.Buffer; | ||
| 4 | import com.strobel.assembler.metadata.ITypeLoader; | ||
| 5 | |||
| 6 | /** | ||
| 7 | * Typeloader with synchronized tryLoadType method | ||
| 8 | */ | ||
| 9 | public class SynchronizedTypeLoader implements ITypeLoader { | ||
| 10 | private final ITypeLoader delegate; | ||
| 11 | |||
| 12 | public SynchronizedTypeLoader(ITypeLoader delegate) { | ||
| 13 | this.delegate = delegate; | ||
| 14 | } | ||
| 15 | |||
| 16 | @Override | ||
| 17 | public synchronized boolean tryLoadType(String internalName, Buffer buffer) { | ||
| 18 | return delegate.tryLoadType(internalName, buffer); | ||
| 19 | } | ||
| 20 | } | ||