diff options
| author | 2020-03-09 06:04:08 -0400 | |
|---|---|---|
| committer | 2020-03-09 10:04:08 +0000 | |
| commit | 58c0aeb15a65324de08a914dfa62cc68a516a4e3 (patch) | |
| tree | f45e8141c0864692051149a478c5a0a6bbe68686 /src/main/java/oml | |
| parent | Made Enigma gui translatable (#193) (diff) | |
| download | enigma-58c0aeb15a65324de08a914dfa62cc68a516a4e3.tar.gz enigma-58c0aeb15a65324de08a914dfa62cc68a516a4e3.tar.xz enigma-58c0aeb15a65324de08a914dfa62cc68a516a4e3.zip | |
CFR support (#192)
* Add decompiler API
* Add CFR support
Diffstat (limited to 'src/main/java/oml')
6 files changed, 0 insertions, 845 deletions
diff --git a/src/main/java/oml/ExtraClasspathTypeLoader.java b/src/main/java/oml/ExtraClasspathTypeLoader.java deleted file mode 100644 index f8ec2e0c..00000000 --- a/src/main/java/oml/ExtraClasspathTypeLoader.java +++ /dev/null | |||
| @@ -1,59 +0,0 @@ | |||
| 1 | package oml; | ||
| 2 | |||
| 3 | import com.strobel.assembler.metadata.Buffer; | ||
| 4 | import com.strobel.assembler.metadata.ITypeLoader; | ||
| 5 | |||
| 6 | import java.io.File; | ||
| 7 | import java.io.IOException; | ||
| 8 | import java.io.InputStream; | ||
| 9 | import java.net.MalformedURLException; | ||
| 10 | import java.net.URL; | ||
| 11 | import java.net.URLClassLoader; | ||
| 12 | import java.util.Arrays; | ||
| 13 | |||
| 14 | /** | ||
| 15 | * Copy of ClasspathTypeLoader supporting a classpath constructor. | ||
| 16 | */ | ||
| 17 | public class ExtraClasspathTypeLoader implements ITypeLoader { | ||
| 18 | private final ClassLoader _loader; | ||
| 19 | |||
| 20 | public ExtraClasspathTypeLoader(String extraClasspath){ | ||
| 21 | _loader = new URLClassLoader(Arrays.stream(extraClasspath.split(File.pathSeparator)).map(path-> { | ||
| 22 | try { | ||
| 23 | return new File(path).toURI().toURL(); | ||
| 24 | } catch (MalformedURLException e) { | ||
| 25 | throw new RuntimeException(e); | ||
| 26 | } | ||
| 27 | }).toArray(URL[]::new)); | ||
| 28 | } | ||
| 29 | |||
| 30 | @Override | ||
| 31 | public boolean tryLoadType(final String internalName, final Buffer buffer) { | ||
| 32 | |||
| 33 | final String path = internalName.concat(".class"); | ||
| 34 | final URL resource = _loader.getResource(path); | ||
| 35 | |||
| 36 | if (resource == null) { | ||
| 37 | return false; | ||
| 38 | } | ||
| 39 | |||
| 40 | try (final InputStream stream = _loader.getResourceAsStream(path)) { | ||
| 41 | final byte[] temp = new byte[4096]; | ||
| 42 | |||
| 43 | int bytesRead; | ||
| 44 | |||
| 45 | while ((bytesRead = stream.read(temp, 0, temp.length)) > 0) { | ||
| 46 | //buffer.ensureWriteableBytes(bytesRead); | ||
| 47 | buffer.putByteArray(temp, 0, bytesRead); | ||
| 48 | } | ||
| 49 | |||
| 50 | buffer.flip(); | ||
| 51 | |||
| 52 | |||
| 53 | return true; | ||
| 54 | } | ||
| 55 | catch (final IOException ignored) { | ||
| 56 | return false; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
diff --git a/src/main/java/oml/ast/transformers/InvalidIdentifierFix.java b/src/main/java/oml/ast/transformers/InvalidIdentifierFix.java deleted file mode 100644 index 3e052ded..00000000 --- a/src/main/java/oml/ast/transformers/InvalidIdentifierFix.java +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | package oml.ast.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/oml/ast/transformers/Java8Generics.java b/src/main/java/oml/ast/transformers/Java8Generics.java deleted file mode 100644 index 0f8a84c1..00000000 --- a/src/main/java/oml/ast/transformers/Java8Generics.java +++ /dev/null | |||
| @@ -1,107 +0,0 @@ | |||
| 1 | package oml.ast.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/oml/ast/transformers/ObfuscatedEnumSwitchRewriterTransform.java b/src/main/java/oml/ast/transformers/ObfuscatedEnumSwitchRewriterTransform.java deleted file mode 100644 index 6005b7f7..00000000 --- a/src/main/java/oml/ast/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 oml.ast.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/oml/ast/transformers/RemoveObjectCasts.java b/src/main/java/oml/ast/transformers/RemoveObjectCasts.java deleted file mode 100644 index d7c3c4a6..00000000 --- a/src/main/java/oml/ast/transformers/RemoveObjectCasts.java +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | package oml.ast.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/oml/ast/transformers/VarargsFixer.java b/src/main/java/oml/ast/transformers/VarargsFixer.java deleted file mode 100644 index 5810373d..00000000 --- a/src/main/java/oml/ast/transformers/VarargsFixer.java +++ /dev/null | |||
| @@ -1,197 +0,0 @@ | |||
| 1 | package oml.ast.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 | } | ||