diff options
Diffstat (limited to 'src/main/java/oml')
3 files changed, 333 insertions, 0 deletions
diff --git a/src/main/java/oml/ast/transformers/InvalidIdentifierFix.java b/src/main/java/oml/ast/transformers/InvalidIdentifierFix.java new file mode 100644 index 00000000..3e052ded --- /dev/null +++ b/src/main/java/oml/ast/transformers/InvalidIdentifierFix.java | |||
| @@ -0,0 +1,29 @@ | |||
| 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 new file mode 100644 index 00000000..0f8a84c1 --- /dev/null +++ b/src/main/java/oml/ast/transformers/Java8Generics.java | |||
| @@ -0,0 +1,107 @@ | |||
| 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/VaragsFixer.java b/src/main/java/oml/ast/transformers/VaragsFixer.java new file mode 100644 index 00000000..cd711ae0 --- /dev/null +++ b/src/main/java/oml/ast/transformers/VaragsFixer.java | |||
| @@ -0,0 +1,197 @@ | |||
| 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 VaragsFixer implements IAstTransform { | ||
| 36 | private final DecompilerContext _context; | ||
| 37 | |||
| 38 | public VaragsFixer(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 | } | ||