Skip to content

Commit d2dbd9e

Browse files
committed
Add AddUnusedParam to the transformer
Currently only appends parameters to the end of the signature but could be extended in the future to inserting at a specific index.
1 parent a2671e5 commit d2dbd9e

File tree

10 files changed

+216
-27
lines changed

10 files changed

+216
-27
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.github.notstirred.dasm.api.annotations.transform;
2+
3+
import io.github.notstirred.dasm.api.annotations.selector.Ref;
4+
5+
import java.lang.annotation.ElementType;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
10+
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
11+
@Retention(RetentionPolicy.CLASS)
12+
public @interface AddUnusedParam {
13+
Ref type();
14+
}

src/main/java/io/github/notstirred/dasm/annotation/AnnotationParser.java

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@
99
import io.github.notstirred.dasm.api.annotations.redirect.redirects.AddFieldToSets;
1010
import io.github.notstirred.dasm.api.annotations.redirect.redirects.AddMethodToSets;
1111
import io.github.notstirred.dasm.api.annotations.redirect.redirects.AddTransformToSets;
12-
import io.github.notstirred.dasm.api.annotations.transform.ApplicationStage;
13-
import io.github.notstirred.dasm.api.annotations.transform.TransformFromClass;
14-
import io.github.notstirred.dasm.api.annotations.transform.TransformFromMethod;
15-
import io.github.notstirred.dasm.api.annotations.transform.TransformMethod;
12+
import io.github.notstirred.dasm.api.annotations.transform.*;
1613
import io.github.notstirred.dasm.data.ClassMethod;
1714
import io.github.notstirred.dasm.exception.DasmException;
1815
import io.github.notstirred.dasm.exception.NoSuchTypeExists;
@@ -24,6 +21,7 @@
2421
import io.github.notstirred.dasm.transformer.data.MethodTransform;
2522
import io.github.notstirred.dasm.util.ClassNodeProvider;
2623
import io.github.notstirred.dasm.util.TypeUtil;
24+
import org.jetbrains.annotations.NotNull;
2725
import org.jetbrains.annotations.Nullable;
2826
import org.objectweb.asm.Opcodes;
2927
import org.objectweb.asm.Type;
@@ -35,8 +33,7 @@
3533
import java.util.*;
3634
import java.util.stream.Collectors;
3735

38-
import static io.github.notstirred.dasm.annotation.AnnotationUtil.getAnnotationIfPresent;
39-
import static io.github.notstirred.dasm.annotation.AnnotationUtil.getAnnotationValues;
36+
import static io.github.notstirred.dasm.annotation.AnnotationUtil.*;
4037
import static org.objectweb.asm.Opcodes.ACC_INTERFACE;
4138
import static org.objectweb.asm.Opcodes.ACC_STATIC;
4239

@@ -145,7 +142,9 @@ public Optional<Collection<MethodTransform>> buildMethodTargets(ClassNode target
145142
List<MethodTransform> methodTransforms = new ArrayList<>();
146143

147144
for (MethodNode method : targetClass.methods) {
148-
TransformMethodImpl transformMethod = parseTransformMethod(method, classExceptions);
145+
DasmMethodExceptions methodExceptions = classExceptions.addNested(new DasmMethodExceptions(method));
146+
147+
TransformMethodImpl transformMethod = parseTransformMethod(method, methodExceptions);
149148
if (transformMethod == null)
150149
continue;
151150

@@ -162,14 +161,17 @@ public Optional<Collection<MethodTransform>> buildMethodTargets(ClassNode target
162161
String nonPrefixedMethodName = method.name;
163162
String prefixedMethodName = methodPrefix + nonPrefixedMethodName;
164163

164+
List<AddedParameter> addedParameters = getAddedParameters(method, methodExceptions);
165+
165166
MethodTransform transform = new MethodTransform(
166167
new ClassMethod(methodOwner, methodOwner, transformMethod.srcMethod()),
167168
prefixedMethodName // We have to rename constructors because we add a prefix, and mixin expects that anything with <> is either init, or clinit
168169
.replace("<init>", "__init__")
169170
.replace("<clinit>", "__clinit__"),
170171
redirectSets,
171172
transformMethod.stage(),
172-
transformMethod.inPlace()
173+
transformMethod.inPlace(),
174+
addedParameters
173175
);
174176

175177
AnnotationNode addToSetsAnnotation = getAnnotationIfPresent(method.invisibleAnnotations, AddTransformToSets.class);
@@ -188,27 +190,46 @@ public Optional<Collection<MethodTransform>> buildMethodTargets(ClassNode target
188190

189191
methodTransforms.add(transform);
190192
}
193+
classExceptions.throwIfHasWrapped();
191194
return Optional.of(methodTransforms);
192195
}
193196

194197
classExceptions.throwIfHasWrapped();
195198
return Optional.empty();
196199
}
197200

201+
/**
202+
* @param method The method to look for annotations on
203+
* @param methodExceptions The object to add nested exceptions to if they occur
204+
* @return The requested parameters to add to the transformed method in order.
205+
*/
206+
@NotNull
207+
private static List<AddedParameter> getAddedParameters(MethodNode method, DasmMethodExceptions methodExceptions) {
208+
List<AnnotationNode> addUnusedParamAnnotations = getAllAnnotations(method.invisibleAnnotations, AddUnusedParam.class);
209+
List<AddedParameter> addedParameters = new ArrayList<>();
210+
for (AnnotationNode annotation : addUnusedParamAnnotations) {
211+
try {
212+
addedParameters.add(AddedParameter.parse(annotation));
213+
} catch (RefImpl.RefAnnotationGivenNoArguments e) {
214+
methodExceptions.addException(e);
215+
}
216+
}
217+
return addedParameters;
218+
}
219+
198220
/**
199221
* @param method The method on which to look for annotations
200-
* @param classExceptions The object to add nested exceptions to if they occur
222+
* @param methodExceptions The object to add nested exceptions to if they occur
201223
* @return null if there was no annotation or there was an exception
202224
*/
203225
@Nullable
204-
private static TransformMethodImpl parseTransformMethod(MethodNode method, DasmClassExceptions classExceptions) {
226+
private static TransformMethodImpl parseTransformMethod(MethodNode method, DasmMethodExceptions methodExceptions) {
205227
TransformMethodImpl transformMethod;
206228
AnnotationNode transformFromMethodAnnotation = getAnnotationIfPresent(method.invisibleAnnotations, TransformFromMethod.class);
207229
AnnotationNode transformMethodAnnotation = getAnnotationIfPresent(method.invisibleAnnotations, TransformMethod.class);
208230
if (transformFromMethodAnnotation == null && transformMethodAnnotation == null) {
209231
return null;
210232
}
211-
DasmMethodExceptions methodExceptions = classExceptions.addNested(new DasmMethodExceptions(method));
212233
if (transformFromMethodAnnotation != null && transformMethodAnnotation != null) {
213234
methodExceptions.addException(new BothTransformMethodAndTransformFromMethodPresent(method));
214235
return null;

src/main/java/io/github/notstirred/dasm/annotation/AnnotationUtil.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.github.notstirred.dasm.annotation;
22

33
import com.google.common.collect.Lists;
4+
import org.jetbrains.annotations.NotNull;
45
import org.jetbrains.annotations.Nullable;
56
import org.objectweb.asm.Type;
67
import org.objectweb.asm.tree.AnnotationNode;
@@ -36,6 +37,20 @@ public static AnnotationNode getAnnotationIfPresent(List<AnnotationNode> annotat
3637
return null;
3738
}
3839

40+
@NotNull
41+
public static List<AnnotationNode> getAllAnnotations(List<AnnotationNode> annotations, Class<?> annotation) {
42+
List<AnnotationNode> annotationsOfType = new ArrayList<>();
43+
if (annotations == null) {
44+
return annotationsOfType;
45+
}
46+
for (AnnotationNode annotationNode : annotations) {
47+
if (annotationNode.desc.equals(classToDescriptor(annotation))) {
48+
annotationsOfType.add(annotationNode);
49+
}
50+
}
51+
return annotationsOfType;
52+
}
53+
3954
public boolean isAnnotationIfPresent(List<AnnotationNode> annotations, Class<?> annotation) {
4055
if (annotations == null) {
4156
return false;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.github.notstirred.dasm.annotation.parse;
2+
3+
import io.github.notstirred.dasm.annotation.AnnotationUtil;
4+
import io.github.notstirred.dasm.api.annotations.transform.AddUnusedParam;
5+
import lombok.Value;
6+
import org.objectweb.asm.Type;
7+
import org.objectweb.asm.tree.AnnotationNode;
8+
9+
import java.util.Map;
10+
11+
@Value
12+
public class AddedParameter {
13+
Type type;
14+
15+
public static AddedParameter parse(AnnotationNode annotation) throws RefImpl.RefAnnotationGivenNoArguments {
16+
Map<String, Object> values = AnnotationUtil.getAnnotationValues(annotation, AddUnusedParam.class);
17+
18+
Type type = RefImpl.parseRefAnnotation("type", values);
19+
return new AddedParameter(type);
20+
}
21+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package io.github.notstirred.dasm.transformer;
2+
3+
import io.github.notstirred.dasm.annotation.parse.AddedParameter;
4+
import org.objectweb.asm.Label;
5+
import org.objectweb.asm.MethodVisitor;
6+
7+
import java.util.List;
8+
9+
import static org.objectweb.asm.Opcodes.ASM9;
10+
11+
public class ParameterAdder extends MethodVisitor {
12+
private final List<AddedParameter> addedParameters;
13+
14+
private int localVariables;
15+
16+
private int maxStack;
17+
private int maxLocals;
18+
19+
private Label startLabel;
20+
private Label endLabel;
21+
22+
public ParameterAdder(MethodVisitor visitor, List<AddedParameter> addedParameters) {
23+
super(ASM9, visitor);
24+
25+
this.addedParameters = addedParameters;
26+
}
27+
28+
@Override
29+
public void visitLabel(Label label) {
30+
super.visitLabel(label);
31+
32+
if (this.startLabel == null) {
33+
this.startLabel = label;
34+
}
35+
this.endLabel = label;
36+
}
37+
38+
@Override
39+
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
40+
super.visitLocalVariable(name, descriptor, signature, start, end, index);
41+
this.localVariables++;
42+
}
43+
44+
@Override
45+
public void visitMaxs(int maxStack, int maxLocals) {
46+
this.maxStack = maxStack;
47+
this.maxLocals = maxLocals;
48+
}
49+
50+
@Override
51+
public void visitEnd() {
52+
for (AddedParameter addedParameter : this.addedParameters) {
53+
super.visitLocalVariable("foo", addedParameter.type().getDescriptor(), null, this.startLabel, this.endLabel, this.localVariables);
54+
}
55+
super.visitMaxs(this.maxStack, this.maxLocals + this.addedParameters.size());
56+
super.visitEnd();
57+
}
58+
}

src/main/java/io/github/notstirred/dasm/transformer/Transformer.java

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.github.notstirred.dasm.transformer;
22

3+
import io.github.notstirred.dasm.annotation.parse.AddedParameter;
34
import io.github.notstirred.dasm.annotation.parse.redirects.FieldRedirectImpl;
45
import io.github.notstirred.dasm.annotation.parse.redirects.MethodRedirectImpl;
56
import io.github.notstirred.dasm.api.provider.MappingsProvider;
@@ -23,9 +24,7 @@
2324
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
2425
import org.objectweb.asm.tree.MethodNode;
2526

26-
import java.util.Collection;
27-
import java.util.HashMap;
28-
import java.util.Map;
27+
import java.util.*;
2928

3029
import static org.objectweb.asm.Opcodes.*;
3130
import static org.objectweb.asm.Type.getObjectType;
@@ -100,12 +99,13 @@ public void transform(ClassNode targetClass, ClassTransform transform) throws No
10099
MethodRedirectImpl methodRedirect = builtRedirects.methodRedirects().get(key);
101100
String dstName = methodRedirect == null ? name : methodRedirect.dstName();
102101

103-
String redirectedDescriptor = applyTransformsToMethodDescriptor(descriptor, redirects);
102+
String redirectedDescriptor = applyTransformsToMethodDescriptor(descriptor, redirects, Collections.emptyList());
104103

105104
return dasmTransformingVisitor(
106105
super.visitMethod(access, dstName, redirectedDescriptor, signature, exceptions),
107106
redirects,
108-
mappingsProvider
107+
mappingsProvider,
108+
Collections.emptyList()
109109
);
110110
}
111111
};
@@ -137,9 +137,9 @@ public void transform(ClassNode targetClass, Collection<MethodTransform> transfo
137137
TransformRedirects transformRedirects = new TransformRedirects(transform.redirectSets(), this.mappingsProvider);
138138
try {
139139
if (transform.inPlace()) {
140-
applyRedirects(srcClass, transform.srcMethod(), transformRedirects, true);
140+
applyRedirects(srcClass, transform.srcMethod(), transformRedirects, transform.addedParameters(), true);
141141
} else {
142-
cloneAndApplyRedirects(srcClass, targetClass, transform.srcMethod(), transform.dstMethodName(), transformRedirects, true);
142+
cloneAndApplyRedirects(srcClass, targetClass, transform.srcMethod(), transform.dstMethodName(), transformRedirects, transform.addedParameters(), true);
143143
}
144144

145145
} catch (SrcMethodNotFound e) {
@@ -155,7 +155,7 @@ public void transform(ClassNode targetClass, Collection<MethodTransform> transfo
155155
* @param redirects lambda redirects are implicitly added, so the parameter is modified.
156156
*/
157157
private MethodNode cloneAndApplyRedirects(ClassNode srcClass, ClassNode targetClass, ClassMethod srcMethod, String dstMethodName,
158-
TransformRedirects redirects, boolean debugLogging) throws SrcMethodNotFound {
158+
TransformRedirects redirects, List<AddedParameter> addedParameters, boolean debugLogging) throws SrcMethodNotFound {
159159
Method existingMethod = srcMethod.remap(this.mappingsProvider).method();
160160

161161
MethodNode srcMethodNode = srcClass.methods.stream()
@@ -164,7 +164,7 @@ private MethodNode cloneAndApplyRedirects(ClassNode srcClass, ClassNode targetCl
164164

165165
cloneAndApplyLambdaRedirects(srcClass, targetClass, srcMethodNode, redirects, debugLogging);
166166

167-
String dstMethodDescriptor = applyTransformsToMethodDescriptor(srcMethodNode.desc, redirects);
167+
String dstMethodDescriptor = applyTransformsToMethodDescriptor(srcMethodNode.desc, redirects, addedParameters);
168168

169169
MethodNode existingMethodNode = removeExistingMethod(targetClass, dstMethodName, dstMethodDescriptor);
170170
if (existingMethodNode != null && (existingMethodNode.access & ACC_NATIVE) == 0) {
@@ -173,7 +173,7 @@ private MethodNode cloneAndApplyRedirects(ClassNode srcClass, ClassNode targetCl
173173
// FIXME: transform exceptions
174174
MethodNode dstMethodNode = new MethodNode(srcMethodNode.access, dstMethodName, dstMethodDescriptor, null, srcMethodNode.exceptions.toArray(new String[0]));
175175

176-
srcMethodNode.accept(dasmTransformingVisitor(dstMethodNode, redirects, mappingsProvider));
176+
srcMethodNode.accept(dasmTransformingVisitor(dstMethodNode, redirects, mappingsProvider, addedParameters));
177177

178178
dstMethodNode.name = dstMethodName;
179179

@@ -184,16 +184,19 @@ private MethodNode cloneAndApplyRedirects(ClassNode srcClass, ClassNode targetCl
184184
/**
185185
* Apply all dasm transforms to a method body
186186
*/
187-
private static MethodVisitor dasmTransformingVisitor(MethodVisitor visitor, TransformRedirects redirects, MappingsProvider mappingsProvider) {
187+
private static MethodVisitor dasmTransformingVisitor(MethodVisitor visitor, TransformRedirects redirects, MappingsProvider mappingsProvider,
188+
List<AddedParameter> addedParameters) {
188189
// FIXME: line numbers
190+
visitor = new ParameterAdder(visitor, addedParameters);
189191
visitor = new Interfacicitifier(visitor, redirects);
190192
visitor = new MethodRemapper(visitor, new TypeRemapper(redirects.typeRedirects(), false, mappingsProvider));
191193
visitor = new RedirectVisitor(visitor, redirects, mappingsProvider);
192194
visitor = new ConstructorToFactoryBufferingVisitor(visitor, redirects);
193195
return visitor;
194196
}
195197

196-
private static String applyTransformsToMethodDescriptor(String methodDescriptor, TransformRedirects redirects) {
198+
private static String applyTransformsToMethodDescriptor(String methodDescriptor, TransformRedirects redirects,
199+
List<AddedParameter> addedParameters) {
197200
Type[] parameterTypes = Type.getArgumentTypes(methodDescriptor);
198201
Type returnType = Type.getReturnType(methodDescriptor);
199202

@@ -208,7 +211,12 @@ private static String applyTransformsToMethodDescriptor(String methodDescriptor,
208211
returnType = redirects.typeRedirects().getOrDefault(returnType, new TypeAndIsInterface(returnType, false)).type();
209212
}
210213

211-
return Type.getMethodDescriptor(returnType, parameterTypes);
214+
List<Type> parameterTypeList = new ArrayList<>(Arrays.asList(parameterTypes));
215+
for (AddedParameter addedParameter : addedParameters) {
216+
parameterTypeList.add(addedParameter.type());
217+
}
218+
219+
return Type.getMethodDescriptor(returnType, parameterTypeList.toArray(new Type[0]));
212220
}
213221

214222
private void cloneAndApplyLambdaRedirects(ClassNode srcClass, ClassNode targetClass, MethodNode method, TransformRedirects redirects,
@@ -245,6 +253,7 @@ private void cloneAndApplyLambdaRedirects(ClassNode srcClass, ClassNode targetCl
245253
new ClassMethod(Type.getObjectType(handle.getOwner()), new Method(name, desc)),
246254
newName,
247255
redirects,
256+
Collections.emptyList(),
248257
debugLogging
249258
);
250259
}
@@ -266,7 +275,7 @@ private void cloneAndApplyLambdaRedirects(ClassNode srcClass, ClassNode targetCl
266275
}
267276

268277
private void applyRedirects(ClassNode srcClass, ClassMethod srcMethod, TransformRedirects redirects,
269-
boolean debugLogging) throws SrcMethodNotFound {
278+
List<AddedParameter> addedParameters, boolean debugLogging) throws SrcMethodNotFound {
270279
Method existingMethod = srcMethod.remap(this.mappingsProvider).method();
271280

272281
MethodNode originalMethod = srcClass.methods.stream()
@@ -275,7 +284,7 @@ private void applyRedirects(ClassNode srcClass, ClassMethod srcMethod, Transform
275284

276285
applyLambdaRedirects(srcClass, originalMethod, redirects, debugLogging);
277286

278-
String dstMethodDescriptor = applyTransformsToMethodDescriptor(originalMethod.desc, redirects);
287+
String dstMethodDescriptor = applyTransformsToMethodDescriptor(originalMethod.desc, redirects, addedParameters);
279288

280289
MethodNode existingMethodNode = removeExistingMethod(srcClass, originalMethod.name, dstMethodDescriptor);
281290
if (existingMethodNode != null && (existingMethodNode.access & ACC_NATIVE) == 0 && !originalMethod.desc.equals(dstMethodDescriptor)) {
@@ -285,7 +294,7 @@ private void applyRedirects(ClassNode srcClass, ClassMethod srcMethod, Transform
285294

286295
MethodNode dstMethodNode = new MethodNode(originalMethod.access, originalMethod.name, dstMethodDescriptor, null, originalMethod.exceptions.toArray(new String[0]));
287296
originalMethod.accept(
288-
dasmTransformingVisitor(dstMethodNode, redirects, mappingsProvider)
297+
dasmTransformingVisitor(dstMethodNode, redirects, mappingsProvider, addedParameters)
289298
);
290299
srcClass.methods.remove(originalMethod);
291300
srcClass.methods.add(dstMethodNode);
@@ -320,6 +329,7 @@ private void applyLambdaRedirects(ClassNode srcClass, MethodNode method, Transfo
320329
srcClass,
321330
new ClassMethod(Type.getObjectType(handle.getOwner()), new Method(name, desc)),
322331
redirects,
332+
Collections.emptyList(),
323333
debugLogging
324334
);
325335
}

src/main/java/io/github/notstirred/dasm/transformer/data/MethodTransform.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.github.notstirred.dasm.transformer.data;
22

3+
import io.github.notstirred.dasm.annotation.parse.AddedParameter;
34
import io.github.notstirred.dasm.annotation.parse.RedirectSetImpl;
45
import io.github.notstirred.dasm.api.annotations.transform.ApplicationStage;
56
import io.github.notstirred.dasm.data.ClassMethod;
@@ -14,4 +15,5 @@ public class MethodTransform {
1415
private final List<RedirectSetImpl> redirectSets;
1516
private final ApplicationStage stage;
1617
private final boolean inPlace;
18+
private final List<AddedParameter> addedParameters;
1719
}

0 commit comments

Comments
 (0)