summaryrefslogtreecommitdiff
path: root/src/main/java/oml/ast/transformers/VaragsFixer.java
diff options
context:
space:
mode:
authorGravatar Thiakil2018-07-24 22:36:08 +0800
committerGravatar Thiakil2018-07-24 22:36:08 +0800
commit8537f73abcf45e4380cf86d29404f61f0c9d88fe (patch)
tree4183f6931d0d01d322fb4317eb31794f109bbe36 /src/main/java/oml/ast/transformers/VaragsFixer.java
parentmissed a semicolon (diff)
downloadenigma-8537f73abcf45e4380cf86d29404f61f0c9d88fe.tar.gz
enigma-8537f73abcf45e4380cf86d29404f61f0c9d88fe.tar.xz
enigma-8537f73abcf45e4380cf86d29404f61f0c9d88fe.zip
more custom source transformers
Diffstat (limited to 'src/main/java/oml/ast/transformers/VaragsFixer.java')
-rw-r--r--src/main/java/oml/ast/transformers/VaragsFixer.java197
1 files changed, 197 insertions, 0 deletions
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 @@
1package oml.ast.transformers;
2
3import com.strobel.assembler.metadata.MemberReference;
4import com.strobel.assembler.metadata.MetadataFilters;
5import com.strobel.assembler.metadata.MetadataHelper;
6import com.strobel.assembler.metadata.MethodBinder;
7import com.strobel.assembler.metadata.MethodDefinition;
8import com.strobel.assembler.metadata.MethodReference;
9import com.strobel.assembler.metadata.TypeReference;
10import com.strobel.core.StringUtilities;
11import com.strobel.core.VerifyArgument;
12import com.strobel.decompiler.DecompilerContext;
13import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression;
14import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression;
15import com.strobel.decompiler.languages.java.ast.AstNode;
16import com.strobel.decompiler.languages.java.ast.AstNodeCollection;
17import com.strobel.decompiler.languages.java.ast.CastExpression;
18import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor;
19import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor;
20import com.strobel.decompiler.languages.java.ast.Expression;
21import com.strobel.decompiler.languages.java.ast.InvocationExpression;
22import com.strobel.decompiler.languages.java.ast.JavaResolver;
23import com.strobel.decompiler.languages.java.ast.Keys;
24import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression;
25import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression;
26import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform;
27import com.strobel.decompiler.semantics.ResolveResult;
28
29import java.util.ArrayList;
30import java.util.List;
31
32/**
33 * Created by Thiakil on 12/07/2018.
34 */
35public 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}