From 58c0aeb15a65324de08a914dfa62cc68a516a4e3 Mon Sep 17 00:00:00 2001 From: Runemoro Date: Mon, 9 Mar 2020 06:04:08 -0400 Subject: CFR support (#192) * Add decompiler API * Add CFR support--- .../oml/ast/transformers/InvalidIdentifierFix.java | 29 -- .../java/oml/ast/transformers/Java8Generics.java | 107 ------ .../ObfuscatedEnumSwitchRewriterTransform.java | 414 --------------------- .../oml/ast/transformers/RemoveObjectCasts.java | 39 -- .../java/oml/ast/transformers/VarargsFixer.java | 197 ---------- 5 files changed, 786 deletions(-) delete mode 100644 src/main/java/oml/ast/transformers/InvalidIdentifierFix.java delete mode 100644 src/main/java/oml/ast/transformers/Java8Generics.java delete mode 100644 src/main/java/oml/ast/transformers/ObfuscatedEnumSwitchRewriterTransform.java delete mode 100644 src/main/java/oml/ast/transformers/RemoveObjectCasts.java delete mode 100644 src/main/java/oml/ast/transformers/VarargsFixer.java (limited to 'src/main/java/oml/ast') 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 3e052de..0000000 --- a/src/main/java/oml/ast/transformers/InvalidIdentifierFix.java +++ /dev/null @@ -1,29 +0,0 @@ -package oml.ast.transformers; - -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; -import com.strobel.decompiler.languages.java.ast.Identifier; -import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; - -/** - * Created by Thiakil on 13/07/2018. - */ -public class InvalidIdentifierFix implements IAstTransform { - @Override - public void run(AstNode compilationUnit) { - compilationUnit.acceptVisitor(new Visitor(), null); - } - - class Visitor extends DepthFirstAstVisitor{ - @Override - public Void visitIdentifier(Identifier node, Void data) { - super.visitIdentifier(node, data); - if (node.getName().equals("do") || node.getName().equals("if")){ - Identifier newIdentifier = Identifier.create(node.getName() + "_", node.getStartLocation()); - newIdentifier.copyUserDataFrom(node); - node.replaceWith(newIdentifier); - } - return null; - } - } -} 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 0f8a84c..0000000 --- a/src/main/java/oml/ast/transformers/Java8Generics.java +++ /dev/null @@ -1,107 +0,0 @@ -package oml.ast.transformers; - -import com.strobel.assembler.metadata.BuiltinTypes; -import com.strobel.assembler.metadata.CommonTypeReferences; -import com.strobel.assembler.metadata.Flags; -import com.strobel.assembler.metadata.IGenericInstance; -import com.strobel.assembler.metadata.IMemberDefinition; -import com.strobel.assembler.metadata.JvmType; -import com.strobel.assembler.metadata.MemberReference; -import com.strobel.assembler.metadata.MethodDefinition; -import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.assembler.metadata.TypeReference; -import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.AstNodeCollection; -import com.strobel.decompiler.languages.java.ast.AstType; -import com.strobel.decompiler.languages.java.ast.CastExpression; -import com.strobel.decompiler.languages.java.ast.ComposedType; -import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; -import com.strobel.decompiler.languages.java.ast.Expression; -import com.strobel.decompiler.languages.java.ast.Identifier; -import com.strobel.decompiler.languages.java.ast.InvocationExpression; -import com.strobel.decompiler.languages.java.ast.Keys; -import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.Roles; -import com.strobel.decompiler.languages.java.ast.SimpleType; -import com.strobel.decompiler.languages.java.ast.WildcardType; -import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; - -/** - * Created by Thiakil on 12/07/2018. - */ -public class Java8Generics implements IAstTransform { - - @Override - public void run(AstNode compilationUnit) { - compilationUnit.acceptVisitor(new Visitor(), null); - } - - static class Visitor extends DepthFirstAstVisitor{ - - @Override - public Void visitInvocationExpression(InvocationExpression node, Void data) { - super.visitInvocationExpression(node, data); - if (node.getTarget() instanceof MemberReferenceExpression){ - MemberReferenceExpression referenceExpression = (MemberReferenceExpression) node.getTarget(); - if (referenceExpression.getTypeArguments().stream().map(t->{ - TypeReference tr = t.toTypeReference(); - if (tr.getDeclaringType() != null){//ensure that inner types are resolved so we can get the TypeDefinition below - TypeReference resolved = tr.resolve(); - if (resolved != null) - return resolved; - } - return tr; - }).anyMatch(t -> t.isWildcardType() || (t instanceof TypeDefinition && ((TypeDefinition) t).isAnonymous()))) { - //these are invalid for invocations, let the compiler work it out - referenceExpression.getTypeArguments().clear(); - } else if (referenceExpression.getTypeArguments().stream().allMatch(t->t.toTypeReference().equals(CommonTypeReferences.Object))){ - //all are , thereby redundant and/or bad - referenceExpression.getTypeArguments().clear(); - } - } - return null; - } - - @Override - public Void visitObjectCreationExpression(ObjectCreationExpression node, Void data) { - super.visitObjectCreationExpression(node, data); - AstType type = node.getType(); - if (type instanceof SimpleType && !((SimpleType) type).getTypeArguments().isEmpty()){ - SimpleType simpleType = (SimpleType) type; - AstNodeCollection typeArguments = simpleType.getTypeArguments(); - if (typeArguments.size() == 1 && typeArguments.firstOrNullObject().toTypeReference().equals(CommonTypeReferences.Object)){ - //all are , thereby redundant and/or bad - typeArguments.firstOrNullObject().getChildByRole(Roles.IDENTIFIER).replaceWith(Identifier.create("")); - } - } - return null; - } - - @Override - public Void visitCastExpression(CastExpression node, Void data) { - boolean doReplace = false; - TypeReference typeReference = node.getType().toTypeReference(); - if (typeReference.isArray() && typeReference.getElementType().isGenericType()){ - doReplace = true; - } else if (typeReference.isGenericType()) { - Expression target = node.getExpression(); - if (typeReference instanceof IGenericInstance && ((IGenericInstance)typeReference).getTypeArguments().stream().anyMatch(t->t.isWildcardType())){ - doReplace = true; - } else if (target instanceof InvocationExpression) { - InvocationExpression invocationExpression = (InvocationExpression)target; - if (invocationExpression.getTarget() instanceof MemberReferenceExpression && !((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().isEmpty()) { - ((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().clear(); - doReplace = true; - } - } - } - super.visitCastExpression(node, data); - if (doReplace){ - node.replaceWith(node.getExpression()); - } - return null; - } - } -} 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 6005b7f..0000000 --- a/src/main/java/oml/ast/transformers/ObfuscatedEnumSwitchRewriterTransform.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Originally: - * EnumSwitchRewriterTransform.java - * - * Copyright (c) 2013 Mike Strobel - * - * This source code is based on Mono.Cecil from Jb Evain, Copyright (c) Jb Evain; - * and ILSpy/ICSharpCode from SharpDevelop, Copyright (c) AlphaSierraPapa. - * - * This source code is subject to terms and conditions of the Apache License, Version 2.0. - * A copy of the license can be found in the License.html file at the root of this distribution. - * By using this source code in any fashion, you are agreeing to be bound by the terms of the - * Apache License, Version 2.0. - * - * You must not remove this notice, or any other, from this software. - */ - -package oml.ast.transformers; - -import com.strobel.assembler.metadata.BuiltinTypes; -import com.strobel.assembler.metadata.FieldDefinition; -import com.strobel.assembler.metadata.MethodDefinition; -import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.assembler.metadata.TypeReference; -import com.strobel.core.SafeCloseable; -import com.strobel.core.VerifyArgument; -import com.strobel.decompiler.DecompilerContext; -import com.strobel.decompiler.languages.java.ast.AssignmentExpression; -import com.strobel.decompiler.languages.java.ast.AstBuilder; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.CaseLabel; -import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor; -import com.strobel.decompiler.languages.java.ast.Expression; -import com.strobel.decompiler.languages.java.ast.IdentifierExpression; -import com.strobel.decompiler.languages.java.ast.IndexerExpression; -import com.strobel.decompiler.languages.java.ast.InvocationExpression; -import com.strobel.decompiler.languages.java.ast.Keys; -import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; -import com.strobel.decompiler.languages.java.ast.PrimitiveExpression; -import com.strobel.decompiler.languages.java.ast.SwitchSection; -import com.strobel.decompiler.languages.java.ast.SwitchStatement; -import com.strobel.decompiler.languages.java.ast.TypeDeclaration; -import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; -import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; - -import java.util.ArrayList; -import java.util.IdentityHashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** - * Copy of {@link com.strobel.decompiler.languages.java.ast.transforms.EnumSwitchRewriterTransform} modified to: - * - Not rely on a field containing "$SwitchMap$" (Proguard strips it) - * - Ignore classes *with* SwitchMap$ names (so the original can handle it) - * - Ignores inner synthetics that are not package private - */ -@SuppressWarnings("Duplicates") -public class ObfuscatedEnumSwitchRewriterTransform implements IAstTransform { - private final DecompilerContext _context; - - public ObfuscatedEnumSwitchRewriterTransform(final DecompilerContext context) { - _context = VerifyArgument.notNull(context, "context"); - } - - @Override - public void run(final AstNode compilationUnit) { - compilationUnit.acceptVisitor(new Visitor(_context), null); - } - - private final static class Visitor extends ContextTrackingVisitor { - private final static class SwitchMapInfo { - final String enclosingType; - final Map> switches = new LinkedHashMap<>(); - final Map> mappings = new LinkedHashMap<>(); - - TypeDeclaration enclosingTypeDeclaration; - - SwitchMapInfo(final String enclosingType) { - this.enclosingType = enclosingType; - } - } - - private final Map _switchMaps = new LinkedHashMap<>(); - private boolean _isSwitchMapWrapper; - - protected Visitor(final DecompilerContext context) { - super(context); - } - - @Override - public Void visitTypeDeclaration(final TypeDeclaration typeDeclaration, final Void p) { - final boolean oldIsSwitchMapWrapper = _isSwitchMapWrapper; - final TypeDefinition typeDefinition = typeDeclaration.getUserData(Keys.TYPE_DEFINITION); - final boolean isSwitchMapWrapper = isSwitchMapWrapper(typeDefinition); - - if (isSwitchMapWrapper) { - final String internalName = typeDefinition.getInternalName(); - - SwitchMapInfo info = _switchMaps.get(internalName); - - if (info == null) { - _switchMaps.put(internalName, info = new SwitchMapInfo(internalName)); - } - - info.enclosingTypeDeclaration = typeDeclaration; - } - - _isSwitchMapWrapper = isSwitchMapWrapper; - - try { - super.visitTypeDeclaration(typeDeclaration, p); - } - finally { - _isSwitchMapWrapper = oldIsSwitchMapWrapper; - } - - rewrite(); - - return null; - } - - @Override - public Void visitSwitchStatement(final SwitchStatement node, final Void data) { - final Expression test = node.getExpression(); - - if (test instanceof IndexerExpression) { - final IndexerExpression indexer = (IndexerExpression) test; - final Expression array = indexer.getTarget(); - final Expression argument = indexer.getArgument(); - - if (!(array instanceof MemberReferenceExpression)) { - return super.visitSwitchStatement(node, data); - } - - final MemberReferenceExpression arrayAccess = (MemberReferenceExpression) array; - final Expression arrayOwner = arrayAccess.getTarget(); - final String mapName = arrayAccess.getMemberName(); - - if (mapName == null || mapName.startsWith("$SwitchMap$") || !(arrayOwner instanceof TypeReferenceExpression)) { - return super.visitSwitchStatement(node, data); - } - - final TypeReferenceExpression enclosingTypeExpression = (TypeReferenceExpression) arrayOwner; - final TypeReference enclosingType = enclosingTypeExpression.getType().getUserData(Keys.TYPE_REFERENCE); - - if (!isSwitchMapWrapper(enclosingType) || !(argument instanceof InvocationExpression)) { - return super.visitSwitchStatement(node, data); - } - - final InvocationExpression invocation = (InvocationExpression) argument; - final Expression invocationTarget = invocation.getTarget(); - - if (!(invocationTarget instanceof MemberReferenceExpression)) { - return super.visitSwitchStatement(node, data); - } - - final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget; - - if (!"ordinal".equals(memberReference.getMemberName())) { - return super.visitSwitchStatement(node, data); - } - - final String enclosingTypeName = enclosingType.getInternalName(); - - SwitchMapInfo info = _switchMaps.get(enclosingTypeName); - - if (info == null) { - _switchMaps.put(enclosingTypeName, info = new SwitchMapInfo(enclosingTypeName)); - - final TypeDefinition resolvedType = enclosingType.resolve(); - - if (resolvedType != null) { - AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER); - - if (astBuilder == null) { - astBuilder = new AstBuilder(context); - } - - try (final SafeCloseable importSuppression = astBuilder.suppressImports()) { - final TypeDeclaration declaration = astBuilder.createType(resolvedType); - - declaration.acceptVisitor(this, data); - } - } - } - - List switches = info.switches.get(mapName); - - if (switches == null) { - info.switches.put(mapName, switches = new ArrayList<>()); - } - - switches.add(node); - } - - return super.visitSwitchStatement(node, data); - } - - @Override - public Void visitAssignmentExpression(final AssignmentExpression node, final Void data) { - final TypeDefinition currentType = context.getCurrentType(); - final MethodDefinition currentMethod = context.getCurrentMethod(); - - if (_isSwitchMapWrapper && - currentType != null && - currentMethod != null && - currentMethod.isTypeInitializer()) { - - final Expression left = node.getLeft(); - final Expression right = node.getRight(); - - if (left instanceof IndexerExpression && - right instanceof PrimitiveExpression) { - - String mapName = null; - - final Expression array = ((IndexerExpression) left).getTarget(); - final Expression argument = ((IndexerExpression) left).getArgument(); - - if (array instanceof MemberReferenceExpression) { - mapName = ((MemberReferenceExpression) array).getMemberName(); - } - else if (array instanceof IdentifierExpression) { - mapName = ((IdentifierExpression) array).getIdentifier(); - } - - if (mapName == null || mapName.startsWith("$SwitchMap$")) { - return super.visitAssignmentExpression(node, data); - } - - if (!(argument instanceof InvocationExpression)) { - return super.visitAssignmentExpression(node, data); - } - - final InvocationExpression invocation = (InvocationExpression) argument; - final Expression invocationTarget = invocation.getTarget(); - - if (!(invocationTarget instanceof MemberReferenceExpression)) { - return super.visitAssignmentExpression(node, data); - } - - final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget; - final Expression memberTarget = memberReference.getTarget(); - - if (!(memberTarget instanceof MemberReferenceExpression) || !"ordinal".equals(memberReference.getMemberName())) { - return super.visitAssignmentExpression(node, data); - } - - final MemberReferenceExpression outerMemberReference = (MemberReferenceExpression) memberTarget; - final Expression outerMemberTarget = outerMemberReference.getTarget(); - - if (!(outerMemberTarget instanceof TypeReferenceExpression)) { - return super.visitAssignmentExpression(node, data); - } - - final String enclosingType = currentType.getInternalName(); - - SwitchMapInfo info = _switchMaps.get(enclosingType); - - if (info == null) { - _switchMaps.put(enclosingType, info = new SwitchMapInfo(enclosingType)); - - AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER); - - if (astBuilder == null) { - astBuilder = new AstBuilder(context); - } - - info.enclosingTypeDeclaration = astBuilder.createType(currentType); - } - - final PrimitiveExpression value = (PrimitiveExpression) right; - - assert value.getValue() instanceof Integer; - - Map mapping = info.mappings.get(mapName); - - if (mapping == null) { - info.mappings.put(mapName, mapping = new LinkedHashMap<>()); - } - - final IdentifierExpression enumValue = new IdentifierExpression( Expression.MYSTERY_OFFSET, outerMemberReference.getMemberName()); - - enumValue.putUserData(Keys.MEMBER_REFERENCE, outerMemberReference.getUserData(Keys.MEMBER_REFERENCE)); - - mapping.put(((Number) value.getValue()).intValue(), enumValue); - } - } - - return super.visitAssignmentExpression(node, data); - } - - private void rewrite() { - if (_switchMaps.isEmpty()) { - return; - } - - for (final SwitchMapInfo info : _switchMaps.values()) { - rewrite(info); - } - - // - // Remove switch map type wrappers that are no longer referenced. - // - - outer: - for (final SwitchMapInfo info : _switchMaps.values()) { - for (final String mapName : info.switches.keySet()) { - final List switches = info.switches.get(mapName); - - if (switches != null && !switches.isEmpty()) { - continue outer; - } - } - - final TypeDeclaration enclosingTypeDeclaration = info.enclosingTypeDeclaration; - - if (enclosingTypeDeclaration != null) { - enclosingTypeDeclaration.remove(); - } - } - } - - private void rewrite(final SwitchMapInfo info) { - if (info.switches.isEmpty()) { - return; - } - - for (final String mapName : info.switches.keySet()) { - final List switches = info.switches.get(mapName); - final Map mappings = info.mappings.get(mapName); - - if (switches != null && mappings != null) { - for (int i = 0; i < switches.size(); i++) { - if (rewriteSwitch(switches.get(i), mappings)) { - switches.remove(i--); - } - } - } - } - } - - private boolean rewriteSwitch(final SwitchStatement s, final Map mappings) { - final Map replacements = new IdentityHashMap<>(); - - for (final SwitchSection section : s.getSwitchSections()) { - for (final CaseLabel caseLabel : section.getCaseLabels()) { - final Expression expression = caseLabel.getExpression(); - - if (expression.isNull()) { - continue; - } - - if (expression instanceof PrimitiveExpression) { - final Object value = ((PrimitiveExpression) expression).getValue(); - - if (value instanceof Integer) { - final Expression replacement = mappings.get(value); - - if (replacement != null) { - replacements.put(expression, replacement); - continue; - } - } - } - - // - // If we can't rewrite all cases, we abort. - // - - return false; - } - } - - final IndexerExpression indexer = (IndexerExpression) s.getExpression(); - final InvocationExpression argument = (InvocationExpression) indexer.getArgument(); - final MemberReferenceExpression memberReference = (MemberReferenceExpression) argument.getTarget(); - final Expression newTest = memberReference.getTarget(); - - newTest.remove(); - indexer.replaceWith(newTest); - - for (final Map.Entry entry : replacements.entrySet()) { - entry.getKey().replaceWith(entry.getValue().clone()); - } - - return true; - } - - private static boolean isSwitchMapWrapper(final TypeReference type) { - if (type == null) { - return false; - } - - final TypeDefinition definition = type instanceof TypeDefinition ? (TypeDefinition) type - : type.resolve(); - - if (definition == null || !definition.isSynthetic() || !definition.isInnerClass() || !definition.isPackagePrivate()) { - return false; - } - - for (final FieldDefinition field : definition.getDeclaredFields()) { - if (!field.getName().startsWith("$SwitchMap$") && - BuiltinTypes.Integer.makeArrayType().equals(field.getFieldType())) { - - return true; - } - } - - return false; - } - } -} \ 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 d7c3c4a..0000000 --- a/src/main/java/oml/ast/transformers/RemoveObjectCasts.java +++ /dev/null @@ -1,39 +0,0 @@ -package oml.ast.transformers; - -import com.strobel.assembler.metadata.BuiltinTypes; -import com.strobel.decompiler.DecompilerContext; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.CastExpression; -import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor; -import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; - -/** - * Created by Thiakil on 11/07/2018. - */ -public class RemoveObjectCasts implements IAstTransform { - private final DecompilerContext _context; - - public RemoveObjectCasts(DecompilerContext context) { - _context = context; - } - - @Override - public void run(AstNode compilationUnit) { - compilationUnit.acceptVisitor(new Visitor(_context), null); - } - - private final static class Visitor extends ContextTrackingVisitor{ - - protected Visitor(DecompilerContext context) { - super(context); - } - - @Override - public Void visitCastExpression(CastExpression node, Void data) { - if (node.getType().toTypeReference().equals(BuiltinTypes.Object)){ - node.replaceWith(node.getExpression()); - } - return super.visitCastExpression(node, data); - } - } -} 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 5810373..0000000 --- a/src/main/java/oml/ast/transformers/VarargsFixer.java +++ /dev/null @@ -1,197 +0,0 @@ -package oml.ast.transformers; - -import com.strobel.assembler.metadata.MemberReference; -import com.strobel.assembler.metadata.MetadataFilters; -import com.strobel.assembler.metadata.MetadataHelper; -import com.strobel.assembler.metadata.MethodBinder; -import com.strobel.assembler.metadata.MethodDefinition; -import com.strobel.assembler.metadata.MethodReference; -import com.strobel.assembler.metadata.TypeReference; -import com.strobel.core.StringUtilities; -import com.strobel.core.VerifyArgument; -import com.strobel.decompiler.DecompilerContext; -import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; -import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.AstNodeCollection; -import com.strobel.decompiler.languages.java.ast.CastExpression; -import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor; -import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; -import com.strobel.decompiler.languages.java.ast.Expression; -import com.strobel.decompiler.languages.java.ast.InvocationExpression; -import com.strobel.decompiler.languages.java.ast.JavaResolver; -import com.strobel.decompiler.languages.java.ast.Keys; -import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; -import com.strobel.decompiler.semantics.ResolveResult; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by Thiakil on 12/07/2018. - */ -public class VarargsFixer implements IAstTransform { - private final DecompilerContext _context; - - public VarargsFixer(final DecompilerContext context) { - _context = VerifyArgument.notNull(context, "context"); - } - - @Override - public void run(AstNode compilationUnit) { - compilationUnit.acceptVisitor(new Visitor(_context), null); - } - - class Visitor extends ContextTrackingVisitor { - private final JavaResolver _resolver; - protected Visitor(DecompilerContext context) { - super(context); - _resolver = new JavaResolver(context); - } - - //remove `new Object[0]` on varagrs as the normal tranformer doesnt do them - @Override - public Void visitInvocationExpression(InvocationExpression node, Void data) { - super.visitInvocationExpression(node, data); - MemberReference definition = node.getUserData(Keys.MEMBER_REFERENCE); - if (definition instanceof MethodDefinition && ((MethodDefinition) definition).isVarArgs()){ - AstNodeCollection arguments = node.getArguments(); - Expression lastParam = arguments.lastOrNullObject(); - if (!lastParam.isNull() && lastParam instanceof ArrayCreationExpression){ - ArrayCreationExpression varargArray = (ArrayCreationExpression)lastParam; - if (varargArray.getInitializer().isNull() || varargArray.getInitializer().getElements().isEmpty()){ - lastParam.remove(); - } else { - for (Expression e : varargArray.getInitializer().getElements()){ - arguments.insertBefore(varargArray, e.clone()); - } - varargArray.remove(); - } - } - } - return null; - } - - //applies the vararg transform to object creation - @Override - public Void visitObjectCreationExpression(ObjectCreationExpression node, Void data) { - super.visitObjectCreationExpression(node, data); - final AstNodeCollection arguments = node.getArguments(); - final Expression lastArgument = arguments.lastOrNullObject(); - - Expression arrayArg = lastArgument; - - if (arrayArg instanceof CastExpression) - arrayArg = ((CastExpression) arrayArg).getExpression(); - - if (arrayArg == null || - arrayArg.isNull() || - !(arrayArg instanceof ArrayCreationExpression && - node.getTarget() instanceof MemberReferenceExpression)) { - - return null; - } - - final ArrayCreationExpression newArray = (ArrayCreationExpression) arrayArg; - final MemberReferenceExpression target = (MemberReferenceExpression) node.getTarget(); - - if (!newArray.getAdditionalArraySpecifiers().hasSingleElement()) { - return null; - } - - final MethodReference method = (MethodReference) node.getUserData(Keys.MEMBER_REFERENCE); - - if (method == null) { - return null; - } - - final MethodDefinition resolved = method.resolve(); - - if (resolved == null || !resolved.isVarArgs()) { - return null; - } - - final List candidates; - final Expression invocationTarget = target.getTarget(); - - if (invocationTarget == null || invocationTarget.isNull()) { - candidates = MetadataHelper.findMethods( - context.getCurrentType(), - MetadataFilters.matchName(resolved.getName()) - ); - } - else { - final ResolveResult targetResult = _resolver.apply(invocationTarget); - - if (targetResult == null || targetResult.getType() == null) { - return null; - } - - candidates = MetadataHelper.findMethods( - targetResult.getType(), - MetadataFilters.matchName(resolved.getName()) - ); - } - - final List argTypes = new ArrayList<>(); - - for (final Expression argument : arguments) { - final ResolveResult argResult = _resolver.apply(argument); - - if (argResult == null || argResult.getType() == null) { - return null; - } - - argTypes.add(argResult.getType()); - } - - final MethodBinder.BindResult c1 = MethodBinder.selectMethod(candidates, argTypes); - - if (c1.isFailure() || c1.isAmbiguous()) { - return null; - } - - argTypes.remove(argTypes.size() - 1); - - final ArrayInitializerExpression initializer = newArray.getInitializer(); - final boolean hasElements = !initializer.isNull() && !initializer.getElements().isEmpty(); - - if (hasElements) { - for (final Expression argument : initializer.getElements()) { - final ResolveResult argResult = _resolver.apply(argument); - - if (argResult == null || argResult.getType() == null) { - return null; - } - - argTypes.add(argResult.getType()); - } - } - - final MethodBinder.BindResult c2 = MethodBinder.selectMethod(candidates, argTypes); - - if (c2.isFailure() || - c2.isAmbiguous() || - !StringUtilities.equals(c2.getMethod().getErasedSignature(), c1.getMethod().getErasedSignature())) { - - return null; - } - - lastArgument.remove(); - - if (!hasElements) { - lastArgument.remove(); - return null; - } - - for (final Expression newArg : initializer.getElements()) { - newArg.remove(); - arguments.add(newArg); - } - - return null; - } - } -} -- cgit v1.2.3