diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5d7242b1..9de00d7b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,11 +16,17 @@ build-job: stage: build script: - $GRADLE build + artifacts: + untracked: true + expire_in: 1 hour test-job: stage: test script: - - $GRADLE test jacocoTestCoverageVerification + - $GRADLE --info test jacocoTestCoverageVerification jacocoTestReport + artifacts: + untracked: true + expire_in: 1 hour deploy-job: stage: deploy @@ -32,4 +38,4 @@ sonar-job: stage: deploy allow_failure: true script: - - if [ $SONAR_LOGIN ]; then $GRADLE -Dorg.gradle.jvmargs='-XX:MetaspaceSize=1024M -XX:MaxMetaspaceSize=1024M' jacocoTestReport sonar -Dsonar.host.url=$SONAR -Dsonar.login=${SONAR_LOGIN}; fi + - if [ $SONAR_LOGIN ]; then $GRADLE --info -Dorg.gradle.jvmargs='-XX:MetaspaceSize=1024M -XX:MaxMetaspaceSize=1024M' sonar -Dsonar.host.url=$SONAR -Dsonar.token=${SONAR_LOGIN}; fi diff --git a/README.md b/README.md index 890fc6a8..bf50faa2 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,14 @@ with [googleJavaFormat](https://github.com/google/google-java-format), [Checkstyle](https://checkstyle.sourceforge.io) and [PMD](https://pmd.github.io). +To fix code formatting errors, you can run the reformat task: + +```shell +./gradle/gradlew spotlessApply +``` + +For more details, see the [Developer Guide](https://asm.ow2.io/developer-guide.html) + ## Reporting Issues If you encounter any issues with the ASM project, please create a new issue diff --git a/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/AnalyzerWithBasicInterpreterTest.java b/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/AnalyzerWithBasicInterpreterTest.java index 3719d7fa..987cbc48 100644 --- a/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/AnalyzerWithBasicInterpreterTest.java +++ b/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/AnalyzerWithBasicInterpreterTest.java @@ -46,7 +46,6 @@ import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.test.AsmTest; -import org.objectweb.asm.test.AsmTest.PrecompiledClass; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; diff --git a/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/AnalyzerWithSimpleVerifierTest.java b/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/AnalyzerWithSimpleVerifierTest.java index 97789abe..985b8c6a 100644 --- a/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/AnalyzerWithSimpleVerifierTest.java +++ b/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/AnalyzerWithSimpleVerifierTest.java @@ -193,7 +193,7 @@ void testAnalyze_classNotFound() { } @Test - void testAnalyze_mergeStackFrames() throws AnalyzerException { + void testAnalyze_mergeStackFrames() { Label loopLabel = new Label(); MethodNode methodNode = new MethodNodeBuilder(1, 4) @@ -223,7 +223,7 @@ void testAnalyze_mergeStackFrames() throws AnalyzerException { } @Test - void testAnalyze_mergeStackFramesWithExceptionHandlers() throws AnalyzerException { + void testAnalyze_mergeStackFramesWithExceptionHandlers() { Label startTry0Label = new Label(); Label endTry0Label = new Label(); Label catch0Label = new Label(); diff --git a/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/MethodNodeBuilder.java b/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/MethodNodeBuilder.java index a87e7f93..07f3cedb 100644 --- a/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/MethodNodeBuilder.java +++ b/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/MethodNodeBuilder.java @@ -94,8 +94,7 @@ MethodNodeBuilder nop() { } MethodNodeBuilder push() { - methodNode.visitInsn(Opcodes.ICONST_0); - return this; + return iconst_0(); } MethodNodeBuilder pop() { diff --git a/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/SmallSetTest.java b/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/SmallSetTest.java index 818b0040..dfe28af4 100644 --- a/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/SmallSetTest.java +++ b/asm-analysis/src/test/java/org/objectweb/asm/tree/analysis/SmallSetTest.java @@ -149,7 +149,7 @@ void testIterator_next_noSuchElement() { iterator.next(); iterator.next(); - Executable next = () -> iterator.next(); + Executable next = iterator::next; assertThrows(NoSuchElementException.class, next); } @@ -159,7 +159,7 @@ void testIterator_remove() { Iterator iterator = newSmallSet(ELEMENT1, ELEMENT2).iterator(); iterator.next(); - assertThrows(UnsupportedOperationException.class, () -> iterator.remove()); + assertThrows(UnsupportedOperationException.class, iterator::remove); } private static SmallSet newSmallSet(final Object element1, final Object element2) { diff --git a/asm-commons/src/main/java/org/objectweb/asm/commons/AnnotationRemapper.java b/asm-commons/src/main/java/org/objectweb/asm/commons/AnnotationRemapper.java index 82204157..5e3bcfe4 100644 --- a/asm-commons/src/main/java/org/objectweb/asm/commons/AnnotationRemapper.java +++ b/asm-commons/src/main/java/org/objectweb/asm/commons/AnnotationRemapper.java @@ -57,7 +57,7 @@ public class AnnotationRemapper extends AnnotationVisitor { * @param remapper the remapper to use to remap the types in the visited annotation. * @deprecated use {@link #AnnotationRemapper(String, AnnotationVisitor, Remapper)} instead. */ - @Deprecated + @Deprecated(forRemoval = false) public AnnotationRemapper(final AnnotationVisitor annotationVisitor, final Remapper remapper) { this(/* descriptor= */ null, annotationVisitor, remapper); } @@ -85,7 +85,7 @@ public AnnotationRemapper( * @param remapper the remapper to use to remap the types in the visited annotation. * @deprecated use {@link #AnnotationRemapper(int, String, AnnotationVisitor, Remapper)} instead. */ - @Deprecated + @Deprecated(forRemoval = false) protected AnnotationRemapper( final int api, final AnnotationVisitor annotationVisitor, final Remapper remapper) { this(api, /* descriptor= */ null, annotationVisitor, remapper); @@ -153,7 +153,7 @@ public AnnotationVisitor visitArray(final @Identifier String name) { * @return the newly created remapper. * @deprecated use {@link #createAnnotationRemapper(String, AnnotationVisitor)} instead. */ - @Deprecated + @Deprecated(forRemoval = false) protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) { return new AnnotationRemapper(api, /* descriptor= */ null, annotationVisitor, remapper); } diff --git a/asm-commons/src/main/java/org/objectweb/asm/commons/ClassRemapper.java b/asm-commons/src/main/java/org/objectweb/asm/commons/ClassRemapper.java index 0a07bff9..f8b45d58 100644 --- a/asm-commons/src/main/java/org/objectweb/asm/commons/ClassRemapper.java +++ b/asm-commons/src/main/java/org/objectweb/asm/commons/ClassRemapper.java @@ -264,7 +264,7 @@ protected MethodVisitor createMethodRemapper(final MethodVisitor methodVisitor) * @return the newly created remapper. * @deprecated use {@link #createAnnotationRemapper(String, AnnotationVisitor)} instead. */ - @Deprecated + @Deprecated(forRemoval = false) protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) { return new AnnotationRemapper(api, /* descriptor= */ null, annotationVisitor, remapper); } diff --git a/asm-commons/src/main/java/org/objectweb/asm/commons/FieldRemapper.java b/asm-commons/src/main/java/org/objectweb/asm/commons/FieldRemapper.java index 34d1d697..be671162 100644 --- a/asm-commons/src/main/java/org/objectweb/asm/commons/FieldRemapper.java +++ b/asm-commons/src/main/java/org/objectweb/asm/commons/FieldRemapper.java @@ -95,7 +95,7 @@ public AnnotationVisitor visitTypeAnnotation( * @return the newly created remapper. * @deprecated use {@link #createAnnotationRemapper(String, AnnotationVisitor)} instead. */ - @Deprecated + @Deprecated(forRemoval = false) protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) { return new AnnotationRemapper(api, /* descriptor= */ null, annotationVisitor, remapper); } diff --git a/asm-commons/src/main/java/org/objectweb/asm/commons/InstructionAdapter.java b/asm-commons/src/main/java/org/objectweb/asm/commons/InstructionAdapter.java index 7b6b57ac..3a2e7335 100644 --- a/asm-commons/src/main/java/org/objectweb/asm/commons/InstructionAdapter.java +++ b/asm-commons/src/main/java/org/objectweb/asm/commons/InstructionAdapter.java @@ -549,6 +549,9 @@ public void visitInvokeDynamicInsn( final @MethodDescriptor String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) { + if (api < Opcodes.ASM5) { + throw new UnsupportedOperationException("This feature requires ASM5"); + } invokedynamic(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); } @@ -1074,8 +1077,8 @@ public void putfield(final @InternalForm String owner, final @Identifier String * @param descriptor the method's descriptor (see {@link Type}). * @deprecated use {@link #invokevirtual(String, String, String, boolean)} instead. */ - @Deprecated - public void invokevirtual(final @InternalForm String owner, final @Identifier String name, final @MethodDescriptor String descriptor) { + @Deprecated(forRemoval = false) + public void invokevirtual(final String owner, final String name, final String descriptor) { if (api >= Opcodes.ASM5) { invokevirtual(owner, name, descriptor, false); return; @@ -1113,8 +1116,8 @@ public void invokevirtual( * @param descriptor the method's descriptor (see {@link Type}). * @deprecated use {@link #invokespecial(String, String, String, boolean)} instead. */ - @Deprecated - public void invokespecial(final @InternalForm String owner, final @Identifier String name, final @MethodDescriptor String descriptor) { + @Deprecated(forRemoval = false) + public void invokespecial(final String owner, final String name, final String descriptor) { if (api >= Opcodes.ASM5) { invokespecial(owner, name, descriptor, false); return; @@ -1152,8 +1155,8 @@ public void invokespecial( * @param descriptor the method's descriptor (see {@link Type}). * @deprecated use {@link #invokestatic(String, String, String, boolean)} instead. */ - @Deprecated - public void invokestatic(final @InternalForm String owner, final @Identifier String name, final @MethodDescriptor String descriptor) { + @Deprecated(forRemoval = false) + public void invokestatic(final String owner, final String name, final String descriptor) { if (api >= Opcodes.ASM5) { invokestatic(owner, name, descriptor, false); return; diff --git a/asm-commons/src/main/java/org/objectweb/asm/commons/MethodRemapper.java b/asm-commons/src/main/java/org/objectweb/asm/commons/MethodRemapper.java index 71a3ee8f..e1119034 100644 --- a/asm-commons/src/main/java/org/objectweb/asm/commons/MethodRemapper.java +++ b/asm-commons/src/main/java/org/objectweb/asm/commons/MethodRemapper.java @@ -175,17 +175,26 @@ public void visitMethodInsn( } @Override + @SuppressWarnings("deprecation") public void visitInvokeDynamicInsn( final String name, final @MethodDescriptor String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) { + String remappedName; + if (remapper.api == 0) { + remappedName = remapper.mapInvokeDynamicMethodName(name, descriptor); + } else { + remappedName = + remapper.mapInvokeDynamicMethodName( + name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); + } Object[] remappedBootstrapMethodArguments = new Object[bootstrapMethodArguments.length]; for (int i = 0; i < bootstrapMethodArguments.length; ++i) { remappedBootstrapMethodArguments[i] = remapper.mapValue(bootstrapMethodArguments[i]); } super.visitInvokeDynamicInsn( - remapper.mapInvokeDynamicMethodName(name, descriptor), + remappedName, remapper.mapMethodDesc(descriptor), (Handle) remapper.mapValue(bootstrapMethodHandle), remappedBootstrapMethodArguments); @@ -274,7 +283,7 @@ public AnnotationVisitor visitLocalVariableAnnotation( * @return the newly created remapper. * @deprecated use {@link #createAnnotationRemapper(String, AnnotationVisitor)} instead. */ - @Deprecated + @Deprecated(forRemoval = false) protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) { return new AnnotationRemapper(api, /* descriptor= */ null, annotationVisitor, remapper); } diff --git a/asm-commons/src/main/java/org/objectweb/asm/commons/RecordComponentRemapper.java b/asm-commons/src/main/java/org/objectweb/asm/commons/RecordComponentRemapper.java index 15721a6b..586dfa07 100644 --- a/asm-commons/src/main/java/org/objectweb/asm/commons/RecordComponentRemapper.java +++ b/asm-commons/src/main/java/org/objectweb/asm/commons/RecordComponentRemapper.java @@ -98,7 +98,7 @@ public AnnotationVisitor visitTypeAnnotation( * @return the newly created remapper. * @deprecated use {@link #createAnnotationRemapper(String, AnnotationVisitor)} instead. */ - @Deprecated + @Deprecated(forRemoval = false) protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) { return new AnnotationRemapper(api, /* descriptor= */ null, annotationVisitor, remapper); } diff --git a/asm-commons/src/main/java/org/objectweb/asm/commons/Remapper.java b/asm-commons/src/main/java/org/objectweb/asm/commons/Remapper.java index acd4c115..edc98613 100644 --- a/asm-commons/src/main/java/org/objectweb/asm/commons/Remapper.java +++ b/asm-commons/src/main/java/org/objectweb/asm/commons/Remapper.java @@ -49,6 +49,55 @@ */ public abstract class Remapper { + // The class name of LambdaMetafactory. + private static final String LAMBDA_FACTORY_CLASSNAME = "java/lang/invoke/LambdaMetafactory"; + + // The method signature of LambdaMetafactory.metafactory(...). + private static final String LAMBDA_FACTORY_METAFACTORY = + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"; + + // The method signature of LambdaMetafactory.altMetafactory(...). + private static final String LAMBDA_FACTORY_ALTMETAFACTORY = + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;" + + "[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + + /** + * The ASM API version supported by this remapper, or 0 for instances created with the deprecated + * constructor. + */ + final int api; + + /** + * Creates a new {@link Remapper}. + * + * @deprecated use {@link #Remapper(int)} instead. + */ + @Deprecated(forRemoval = false) + protected Remapper() { + this.api = 0; + } + + /** + * Creates a new {@link Remapper}. + * + * @param api the ASM API version supported by this remapper. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + */ + protected Remapper(final int api) { + if (api != Opcodes.ASM9 + && api != Opcodes.ASM8 + && api != Opcodes.ASM7 + && api != Opcodes.ASM6 + && api != Opcodes.ASM5 + && api != Opcodes.ASM4 + && api != Opcodes.ASM10_EXPERIMENTAL) { + throw new IllegalArgumentException("Unsupported api " + api); + } + this.api = api; + } + /** * Returns the given descriptor, remapped with {@link #map(String)}. * @@ -188,17 +237,26 @@ public Object mapValue(final Object value) { } if (value instanceof ConstantDynamic) { ConstantDynamic constantDynamic = (ConstantDynamic) value; + String name = constantDynamic.getName(); + String descriptor = constantDynamic.getDescriptor(); + Handle bootstrapMethod = constantDynamic.getBootstrapMethod(); int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount(); + Object[] bootstrapMethodArguments = new Object[bootstrapMethodArgumentCount]; Object[] remappedBootstrapMethodArguments = new Object[bootstrapMethodArgumentCount]; for (int i = 0; i < bootstrapMethodArgumentCount; ++i) { - remappedBootstrapMethodArguments[i] = - mapValue(constantDynamic.getBootstrapMethodArgument(i)); + bootstrapMethodArguments[i] = constantDynamic.getBootstrapMethodArgument(i); + remappedBootstrapMethodArguments[i] = mapValue(bootstrapMethodArguments[i]); + } + if (api == 0) { + name = mapInvokeDynamicMethodName(name, descriptor); + } else { + name = + mapInvokeDynamicMethodName(name, descriptor, bootstrapMethod, bootstrapMethodArguments); } - @FieldDescriptor String descriptor = constantDynamic.getDescriptor(); return new ConstantDynamic( - mapInvokeDynamicMethodName(constantDynamic.getName(), descriptor), + name, mapDesc(descriptor), - (Handle) mapValue(constantDynamic.getBootstrapMethod()), + (Handle) mapValue(bootstrapMethod), remappedBootstrapMethodArguments); } return value; @@ -236,7 +294,7 @@ public String mapSignature(final String signature, final boolean typeSignature) * @return the newly created remapper. * @deprecated use {@link #createSignatureRemapper} instead. */ - @Deprecated + @Deprecated(forRemoval = false) protected SignatureVisitor createRemappingSignatureAdapter( final SignatureVisitor signatureVisitor) { return createSignatureRemapper(signatureVisitor); @@ -288,11 +346,11 @@ protected SignatureVisitor createSignatureRemapper(final SignatureVisitor signat } else { int originSplit = name.lastIndexOf('/'); int remappedSplit = remappedInnerName.lastIndexOf('/'); - if (originSplit != -1 && remappedSplit != -1) { - if (name.substring(originSplit).equals(remappedInnerName.substring(remappedSplit))) { - // class name not changed - return innerName; - } + if (originSplit != -1 + && remappedSplit != -1 + && name.substring(originSplit).equals(remappedInnerName.substring(remappedSplit))) { + // class name not changed + return innerName; } } @@ -329,11 +387,126 @@ protected SignatureVisitor createSignatureRemapper(final SignatureVisitor signat * @param name the name of the method. * @param descriptor the descriptor of the method. * @return the new name of the method. + * @deprecated use {@link #mapInvokeDynamicMethodName(String, String, Handle, Object...)} instead. */ + @Deprecated(forRemoval = false) public String mapInvokeDynamicMethodName(final String name, final String descriptor) { return name; } + /** + * Maps an invokedynamic or a constant dynamic method name to its new name. Subclasses can + * override. + * + *

The default implementation of this method first performs well-known rule checks (calling + * {@link #mapWellKnownInvokeDynamicMethodName(String, String, Handle, Object...)}) and then + * performs basic remapping (calling {@link #mapBasicInvokeDynamicMethodName(String, String, + * Handle, Object...)}). + * + *

For most users, only {@link #mapBasicInvokeDynamicMethodName(String, String, Handle, + * Object...)} needs to be overridden. + * + * @param name the name of the method. + * @param descriptor the descriptor of the method. + * @param bootstrapMethodHandle the bootstrap method. + * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be + * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link + * Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify + * the content of the array so a caller should expect that this array may change. + * @return the new name of the method. + */ + public String mapInvokeDynamicMethodName( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + String mappedWellKnownName = + mapWellKnownInvokeDynamicMethodName( + name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); + if (mappedWellKnownName != null) { + return mappedWellKnownName; + } + return mapBasicInvokeDynamicMethodName( + name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); + } + + /** + * Maps well-known invokedynamic (e.g. lambda creation) or const dynamic method names to their new + * names. This method detects specific invokedynamic method rules and remaps using the + * corresponding rules. When no rule is matched, returns {@literal null}. When non-null is + * returned, it means that this invokedynamic method name matches a rule and has been remapped + * with the relevant rule. Subclasses can override. + * + * @param name the name of the method. + * @param descriptor the descriptor of the method. + * @param bootstrapMethodHandle the bootstrap method. + * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be + * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link + * Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify + * the content of the array so a caller should expect that this array may change. + * @return the new name of the method, or null if no special rule is matched. + */ + public String mapWellKnownInvokeDynamicMethodName( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + + if (LAMBDA_FACTORY_CLASSNAME.equals(bootstrapMethodHandle.getOwner()) + && bootstrapMethodHandle.getTag() == Opcodes.H_INVOKESTATIC) { + // This is a lambda creation. + // Note: **if** is reserved for future JDK changes. + boolean isMetafactory = false; + isMetafactory |= + "metafactory".equals(bootstrapMethodHandle.getName()) + && LAMBDA_FACTORY_METAFACTORY.equals(bootstrapMethodHandle.getDesc()); + isMetafactory |= + "altMetafactory".equals(bootstrapMethodHandle.getName()) + && LAMBDA_FACTORY_ALTMETAFACTORY.equals(bootstrapMethodHandle.getDesc()); + + if (isMetafactory) { + // Note: + // Java lambda instances are created by LambdaMetafactory.metafactory() and + // LambdaMetafactory.altMetafactory(). + // The specification can be found in the LambdaMetafactory javadoc: + // https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/invoke/LambdaMetafactory.html + // + // In short, all the necessary parameters can be obtained from this invokedynamic, including + // the following three: + // - Class name: From return type of method descriptor. + // - Method name: Same as the name of invokedynamic. + // - Method descriptor: From the first bootstrap argument. + return mapMethodName( + Type.getReturnType(descriptor).getInternalName(), + name, + bootstrapMethodArguments[0].toString()); + } + } + + return null; + } + + /** + * Maps an invokedynamic or a constant dynamic method name to its new name. The default + * implementation of this method returns the given name, unchanged. Subclasses can override. + * + * @param name the name of the method. + * @param descriptor the descriptor of the method. + * @param bootstrapMethodHandle the bootstrap method. + * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be + * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link + * Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify + * the content of the array so a caller should expect that this array may change. + * @return the new name of the method. + */ + public String mapBasicInvokeDynamicMethodName( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + return name; + } + /** * Maps a record component name to its new name. The default implementation of this method returns * the given name, unchanged. Subclasses can override. diff --git a/asm-commons/src/main/java/org/objectweb/asm/commons/SerialVersionUIDAdder.java b/asm-commons/src/main/java/org/objectweb/asm/commons/SerialVersionUIDAdder.java index cf51531e..cd27098c 100644 --- a/asm-commons/src/main/java/org/objectweb/asm/commons/SerialVersionUIDAdder.java +++ b/asm-commons/src/main/java/org/objectweb/asm/commons/SerialVersionUIDAdder.java @@ -429,7 +429,7 @@ protected long computeSVUID() throws IOException { // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). protected byte[] computeSHAdigest(final byte[] value) { try { - return MessageDigest.getInstance("SHA").digest(value); + return MessageDigest.getInstance("SHA-1").digest(value); } catch (NoSuchAlgorithmException e) { throw new UnsupportedOperationException(e); } diff --git a/asm-commons/src/main/java/org/objectweb/asm/commons/SimpleRemapper.java b/asm-commons/src/main/java/org/objectweb/asm/commons/SimpleRemapper.java index 790931ed..e8dee4a9 100644 --- a/asm-commons/src/main/java/org/objectweb/asm/commons/SimpleRemapper.java +++ b/asm-commons/src/main/java/org/objectweb/asm/commons/SimpleRemapper.java @@ -35,6 +35,8 @@ import java.util.Collections; import java.util.Map; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Opcodes; /** * A {@link Remapper} using a {@link Map} to define its mapping. @@ -63,11 +65,40 @@ public class SimpleRemapper extends Remapper { *

  • for internal names, the key is the old internal name, and the value is the new * internal name (see {@link org.objectweb.asm.Type#getInternalName()}). * + * + * @deprecated use {@link #SimpleRemapper(int, Map)} instead. */ + @Deprecated(forRemoval = false) public SimpleRemapper(final Map mapping) { this.mapping = mapping; } + /** + * Constructs a new {@link SimpleRemapper} with the given mapping. + * + * @param api the ASM API version supported by this remapper. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + * @param mapping a map specifying a remapping as follows: + *
      + *
    • for method names, the key is the owner, name and descriptor of the method (in the + * form <owner>.<name><descriptor>), and the value is the new method + * name. + *
    • for invokedynamic method names, the key is the name and descriptor of the method (in + * the form .<name><descriptor>), and the value is the new method name. + *
    • for field names, the key is the owner and name of the field or attribute (in the form + * <owner>.<name>), and the value is the new field name. + *
    • for attribute names, the key is the annotation descriptor and the name of the + * attribute (in the form <descriptor>.<name>), and the value is the new + * attribute name. + *
    • for internal names, the key is the old internal name, and the value is the new + * internal name (see {@link org.objectweb.asm.Type#getInternalName()}). + *
    + */ + public SimpleRemapper(final int api, final Map mapping) { + super(api); + this.mapping = mapping; + } + /** * Constructs a new {@link SimpleRemapper} with the given mapping. * @@ -75,11 +106,28 @@ public SimpleRemapper(final Map mapping) { * #SimpleRemapper(Map)} for the format of these keys). * @param newName the new method, field or internal name (see {@link * org.objectweb.asm.Type#getInternalName()}). + * @deprecated use {@link #SimpleRemapper(int, String, String)} instead. */ + @Deprecated(forRemoval = false) public SimpleRemapper(final String oldName, final String newName) { this.mapping = Collections.singletonMap(oldName, newName); } + /** + * Constructs a new {@link SimpleRemapper} with the given mapping. + * + * @param api the ASM API version supported by this remapper. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + * @param oldName the key corresponding to a method, field or internal name (see {@link + * #SimpleRemapper(Map)} for the format of these keys). + * @param newName the new method, field or internal name (see {@link + * org.objectweb.asm.Type#getInternalName()}). + */ + public SimpleRemapper(final int api, final String oldName, final String newName) { + super(api); + this.mapping = Collections.singletonMap(oldName, newName); + } + @Override @SuppressWarnings("signature:return") // TODO: this does not necessarily return an identifier public @Identifier String mapMethodName(final @InternalForm String owner, final @Identifier String name, final String descriptor) { @@ -87,15 +135,33 @@ public SimpleRemapper(final String oldName, final String newName) { return remappedName == null ? name : remappedName; } + /** + * Maps an invokedynamic or a constant dynamic method name to its new name. + * + * @param name the name of the method. + * @param descriptor the descriptor of the method. + * @return the new name of the method. + * @deprecated use {@link #mapInvokeDynamicMethodName(String, String, Handle, Object...)} instead. + */ @Override + @Deprecated(forRemoval = false) public String mapInvokeDynamicMethodName(final String name, final String descriptor) { String remappedName = map('.' + name + descriptor); return remappedName == null ? name : remappedName; } @Override - @SuppressWarnings("signature") // TODO: might not return a dot-separated-identifiers - public @DotSeparatedIdentifiers String mapAnnotationAttributeName(final @FieldDescriptor String descriptor, final String name) { + public String mapBasicInvokeDynamicMethodName( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + String remappedName = map('.' + name + descriptor); + return remappedName == null ? name : remappedName; + } + + @Override + public String mapAnnotationAttributeName(final String descriptor, final String name) { String remappedName = map(descriptor + '.' + name); return remappedName == null ? name : remappedName; } diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/AdviceAdapterTest.java b/asm-commons/src/test/java/org/objectweb/asm/commons/AdviceAdapterTest.java index aac194a4..4102e396 100644 --- a/asm-commons/src/test/java/org/objectweb/asm/commons/AdviceAdapterTest.java +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/AdviceAdapterTest.java @@ -634,7 +634,7 @@ void testAllMethods_constructorWithHandlerFallthroughToPrivateMethodCall() { @ParameterizedTest @MethodSource(ALL_CLASSES_AND_ALL_APIS) void testAllMethods_precompiledClass( - final PrecompiledClass classParameter, final Api apiParameter) throws Exception { + final PrecompiledClass classParameter, final Api apiParameter) { ClassReader classReader = new ClassReader(classParameter.getBytes()); ClassWriter classWriter = new ClassWriter(0); ClassVisitor adviceClassAdapter = @@ -678,9 +678,6 @@ protected void onMethodEnter() { // pop from an empty stack because the previous ICONST_1 was not simulated. visitJumpInsn(IFEQ, label); } - - @Override - protected void onMethodExit(final int opcode) {} }; adviceAdapter.visitCode(); diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/AnalyzerAdapterTest.java b/asm-commons/src/test/java/org/objectweb/asm/commons/AnalyzerAdapterTest.java index 0513f4d4..ea474eda 100644 --- a/asm-commons/src/test/java/org/objectweb/asm/commons/AnalyzerAdapterTest.java +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/AnalyzerAdapterTest.java @@ -95,7 +95,7 @@ void testVisitFrame_invalidFrameType() { @ParameterizedTest @MethodSource(ALL_CLASSES_AND_ALL_APIS) void testAllMethods_precompiledClass( - final PrecompiledClass classParameter, final Api apiParameter) throws Exception { + final PrecompiledClass classParameter, final Api apiParameter) { byte[] classFile = classParameter.getBytes(); ClassReader classReader = new ClassReader(classFile); ClassWriter classWriter = new ClassWriter(0); @@ -201,13 +201,11 @@ public void visitFrame( private void maybeInsertFrame() { // Don't insert a frame if we already have one for this instruction, from the original class. - if (!hasOriginalFrame) { - if (analyzerAdapter.locals != null && analyzerAdapter.stack != null) { - ArrayList local = toFrameTypes(analyzerAdapter.locals); - ArrayList stack = toFrameTypes(analyzerAdapter.stack); - super.visitFrame( - Opcodes.F_NEW, local.size(), local.toArray(), stack.size(), stack.toArray()); - } + if (!hasOriginalFrame && analyzerAdapter.locals != null && analyzerAdapter.stack != null) { + ArrayList local = toFrameTypes(analyzerAdapter.locals); + ArrayList stack = toFrameTypes(analyzerAdapter.stack); + super.visitFrame( + Opcodes.F_NEW, local.size(), local.toArray(), stack.size(), stack.toArray()); } hasOriginalFrame = false; } diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/ClassRemapperTest.java b/asm-commons/src/test/java/org/objectweb/asm/commons/ClassRemapperTest.java index f3128664..22774427 100644 --- a/asm-commons/src/test/java/org/objectweb/asm/commons/ClassRemapperTest.java +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/ClassRemapperTest.java @@ -69,7 +69,9 @@ class ClassRemapperTest extends AsmTest { void testVisit() { ClassNode classNode = new ClassNode(); ClassRemapper classRemapper = - new ClassRemapper(classNode, new SimpleRemapper("pkg/C", "new/pkg/C")); + new ClassRemapper( + classNode, + new SimpleRemapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL, "pkg/C", "new/pkg/C")); classRemapper.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "pkg/C", null, "java/lang/Object", null); @@ -82,7 +84,7 @@ void testVisitAnnotation() { ClassRemapper remapper = new ClassRemapper( classNode, - new Remapper() { + new Remapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL) { @Override public String mapAnnotationAttributeName(final String descriptor, final String name) { if ("Lpkg/A;".equals(descriptor)) { @@ -104,7 +106,7 @@ void testVisitInnerClass() { ClassRemapper remapper = new ClassRemapper( classNode, - new Remapper() { + new Remapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL) { @Override public String map(final @InternalForm String internalName) { if ("pkg/C".equals(internalName)) { @@ -131,7 +133,7 @@ void testVisitInnerClass_localInnerClass() { ClassRemapper remapper = new ClassRemapper( classNode, - new Remapper() { + new Remapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL) { @Override public String map(final @InternalForm String internalName) { if ("pkg/C".equals(internalName)) { @@ -158,7 +160,7 @@ void testVisitInnerClass_specialRemap() { ClassRemapper remapper = new ClassRemapper( classNode, - new Remapper() { + new Remapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL) { @Override public String map(final @InternalForm String internalName) { if ("pkg/C".equals(internalName)) { @@ -185,7 +187,7 @@ void testVisitAttribute_moduleHashes() { ClassRemapper classRemapper = new ClassRemapper( classNode, - new Remapper() { + new Remapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL) { @Override public String mapModuleName(final String name) { return "new." + name; @@ -202,7 +204,8 @@ public String mapModuleName(final String name) { } @Test - void testVisitLdcInsn_constantDynamic() { + @SuppressWarnings("deprecation") + void testVisitLdcInsn_constantDynamic_deprecated() { ClassNode classNode = new ClassNode(); ClassRemapper classRemapper = new ClassRemapper( @@ -243,13 +246,65 @@ public String mapInvokeDynamicMethodName(final String name, final String descrip } @Test - void testInvokeDynamicInsn_field() { + void testVisitLdcInsn_constantDynamic() { + ClassNode classNode = new ClassNode(); + ClassRemapper classRemapper = + new ClassRemapper( + /* latest api */ Opcodes.ASM9, + classNode, + new Remapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL) { + @Override + public String mapBasicInvokeDynamicMethodName( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + return "new." + name; + } + + @Override + public String map(final String internalName) { + if (internalName.equals("java/lang/String")) { + return "java/lang/Integer"; + } + return internalName; + } + }) { + /* inner class so it can access the protected constructor */ + }; + classRemapper.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null); + MethodVisitor methodVisitor = + classRemapper.visitMethod(Opcodes.ACC_PUBLIC, "hello", "()V", null, null); + methodVisitor.visitCode(); + + methodVisitor.visitLdcInsn( + new ConstantDynamic( + "foo", + "Ljava/lang/String;", + new Handle(Opcodes.H_INVOKESTATIC, "BSMHost", "bsm", "()Ljava/lang/String;", false))); + + ConstantDynamic constantDynamic = + (ConstantDynamic) ((LdcInsnNode) classNode.methods.get(0).instructions.get(0)).cst; + assertEquals("new.foo", constantDynamic.getName()); + assertEquals("Ljava/lang/Integer;", constantDynamic.getDescriptor()); + assertEquals("()Ljava/lang/Integer;", constantDynamic.getBootstrapMethod().getDesc()); + } + + @Test + void testInvokeDynamicInsn_field_deprecated() { ClassNode classNode = new ClassNode(); + @SuppressWarnings("deprecation") ClassRemapper classRemapper = new ClassRemapper( /* latest api */ Opcodes.ASM9, classNode, new Remapper() { + @Override + @Deprecated + public String mapInvokeDynamicMethodName(final String name, final String descriptor) { + return "new." + name; + } + @Override public String mapFieldName( final @InternalForm String owner, final String name, final String descriptor) { @@ -271,6 +326,49 @@ public String mapFieldName( InvokeDynamicInsnNode invokeDynamic = (InvokeDynamicInsnNode) classNode.methods.get(0).instructions.get(0); + assertEquals("new.foo", invokeDynamic.name); + assertEquals("demo", invokeDynamic.bsm.getName()); + } + + @Test + void testInvokeDynamicInsn_field() { + ClassNode classNode = new ClassNode(); + ClassRemapper classRemapper = + new ClassRemapper( + /* latest api */ Opcodes.ASM9, + classNode, + new Remapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL) { + @Override + public String mapBasicInvokeDynamicMethodName( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + return "new." + name; + } + + @Override + public String mapFieldName( + final String owner, final String name, final String descriptor) { + if ("a".equals(name)) { + return "demo"; + } + return name; + } + }); + classRemapper.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null); + MethodVisitor methodVisitor = + classRemapper.visitMethod(Opcodes.ACC_PUBLIC, "hello", "()V", null, null); + methodVisitor.visitCode(); + + methodVisitor.visitInvokeDynamicInsn( + "foo", + "()Ljava/lang/String;", + new Handle(Opcodes.H_GETFIELD, "pkg/B", "a", "Ljava/lang/String;", false)); + + InvokeDynamicInsnNode invokeDynamic = + (InvokeDynamicInsnNode) classNode.methods.get(0).instructions.get(0); + assertEquals("new.foo", invokeDynamic.name); assertEquals("demo", invokeDynamic.bsm.getName()); } @@ -283,7 +381,10 @@ void testEmptyClassRemapper_precompiledClass( ClassReader classReader = new ClassReader(classFile); ClassWriter classWriter = new ClassWriter(0); ClassRemapper classRemapper = - newClassRemapper(apiParameter.value(), classWriter, new SimpleRemapper(Map.of())); + newClassRemapper( + apiParameter.value(), + classWriter, + new SimpleRemapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL, Map.of())); Executable accept = () -> classReader.accept(classRemapper, new Attribute[] {new CodeComment()}, 0); @@ -317,7 +418,9 @@ void testEmptyClassRemapper_innerClassNames() { byte[] classFile = classFileWriter.toByteArray(); ClassReader classReader = new ClassReader(classFile); ClassWriter classWriter = new ClassWriter(0); - ClassRemapper classRemapper = new ClassRemapper(classWriter, new SimpleRemapper(Map.of())); + ClassRemapper classRemapper = + new ClassRemapper( + classWriter, new SimpleRemapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL, Map.of())); classReader.accept(classRemapper, new Attribute[] {new CodeComment()}, 0); @@ -408,6 +511,7 @@ static class UpperCaseRemapper extends Remapper { private final String remappedInternalClassName; UpperCaseRemapper(final String internalClassName) { + super(/* latest */ Opcodes.ASM10_EXPERIMENTAL); this.internalClassName = internalClassName; this.remappedInternalClassName = internalClassName.equals("module-info") @@ -443,7 +547,11 @@ String getRemappedClassName() { } @Override - public String mapInvokeDynamicMethodName(final String name, final String descriptor) { + public String mapBasicInvokeDynamicMethodName( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { return name.toUpperCase(LOCALE); } diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/CodeComment.java b/asm-commons/src/test/java/org/objectweb/asm/commons/CodeComment.java index f56ba446..2723e981 100644 --- a/asm-commons/src/test/java/org/objectweb/asm/commons/CodeComment.java +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/CodeComment.java @@ -75,10 +75,4 @@ protected ByteVector write( final int maxLocals) { return new ByteVector(); } - - @Override - protected Label[] getLabels() { - super.getLabels(); - return new Label[] {new Label()}; - } } diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/GeneratorAdapterTest.java b/asm-commons/src/test/java/org/objectweb/asm/commons/GeneratorAdapterTest.java index 3dc50de3..160aba15 100644 --- a/asm-commons/src/test/java/org/objectweb/asm/commons/GeneratorAdapterTest.java +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/GeneratorAdapterTest.java @@ -232,7 +232,7 @@ void testLoadThis() { void testLoadThis_illegalState() { Generator generator = new Generator(Opcodes.ACC_STATIC, "m", "()V"); - Executable loadThis = () -> generator.loadThis(); + Executable loadThis = generator::loadThis; assertThrows(IllegalStateException.class, loadThis); } diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/JsrInlinerAdapterTest.java b/asm-commons/src/test/java/org/objectweb/asm/commons/JsrInlinerAdapterTest.java index cb46e118..9d2387ca 100644 --- a/asm-commons/src/test/java/org/objectweb/asm/commons/JsrInlinerAdapterTest.java +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/JsrInlinerAdapterTest.java @@ -1511,9 +1511,9 @@ void testInlineJsr_precompiledClass( ClassFile classFile = new ClassFile(classWriter.toByteArray()); if (classParameter.isNotCompatibleWithCurrentJdk()) { - assertThrows(UnsupportedClassVersionError.class, () -> classFile.newInstance()); + assertThrows(UnsupportedClassVersionError.class, classFile::newInstance); } else { - assertDoesNotThrow(() -> classFile.newInstance()); + assertDoesNotThrow(classFile::newInstance); } } diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/LambdaRemapTest.java b/asm-commons/src/test/java/org/objectweb/asm/commons/LambdaRemapTest.java new file mode 100644 index 00000000..c5557cd2 --- /dev/null +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/LambdaRemapTest.java @@ -0,0 +1,289 @@ +package org.objectweb.asm.commons; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Map; +import java.util.stream.Stream; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.Parameter; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; +import org.objectweb.asm.Handle; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.test.AsmTest; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; + +@SuppressWarnings("UnnecessaryBoxing") +class LambdaRemapTest extends AsmTest implements Opcodes { + + // The method signature of LambdaMetafactory.metafactory(...). + private static final String LAMBDA_FACTORY_METAFACTORY = + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"; + + // The method signature of LambdaMetafactory.altMetafactory(...). + private static final String LAMBDA_FACTORY_ALTMETAFACTORY = + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;" + + "[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"; + + /* + * The 3 following methods correspond to the following Java code: + * + * public class LambdaTest { + * public interface TestInterface { + * default void helloWorld() {} + * } + * + * public static void normalLambda() { + * Runnable runnable = Thread::dumpStack; + * } + * + * public static void serializableLambda() { + * Runnable runnable = (Runnable & Serializable) Thread::dumpStack; + * } + * + * public static void advancedLambda() { + * Runnable runnable = (Runnable & Serializable & TestInterface) Thread::dumpStack; + * } + * } + */ + + void func_normalLambda(final MethodVisitor methodVisitor) { + methodVisitor.visitInvokeDynamicInsn( + "run", + "()Ljava/lang/Runnable;", + new Handle( + Opcodes.H_INVOKESTATIC, + "java/lang/invoke/LambdaMetafactory", + "metafactory", + LAMBDA_FACTORY_METAFACTORY, + false), + new Object[] { + Type.getType("()V"), + new Handle(Opcodes.H_INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V", false), + Type.getType("()V") + }); + } + + void func_serializableLambda(final MethodVisitor methodVisitor) { + methodVisitor.visitInvokeDynamicInsn( + "run", + "()Ljava/lang/Runnable;", + new Handle( + Opcodes.H_INVOKESTATIC, + "java/lang/invoke/LambdaMetafactory", + "altMetafactory", + LAMBDA_FACTORY_ALTMETAFACTORY, + false), + new Object[] { + Type.getType("()V"), + new Handle(Opcodes.H_INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V", false), + Type.getType("()V"), + Integer.valueOf(5), + Integer.valueOf(0) + }); + } + + void func_advancedLambda(final MethodVisitor methodVisitor) { + methodVisitor.visitInvokeDynamicInsn( + "run", + "()Ljava/lang/Runnable;", + new Handle( + Opcodes.H_INVOKESTATIC, + "java/lang/invoke/LambdaMetafactory", + "altMetafactory", + LAMBDA_FACTORY_ALTMETAFACTORY, + false), + new Object[] { + Type.getType("()V"), + new Handle(Opcodes.H_INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V", false), + Type.getType("()V"), + Integer.valueOf(7), + Integer.valueOf(1), + Type.getType("Lpkg/LambdaTest$TestInterface;"), + Integer.valueOf(0) + }); + } + + public static Stream remappersLatest() { + return Stream.of( + new Remapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL) { + @Override + public String mapMethodName( + final String owner, final String name, final String descriptor) { + if ("java/lang/Runnable".equals(owner) && "run".equals(name)) { + return "call"; + } + return name; + } + + @Override + public String map(final String internalName) { + if ("java/lang/Runnable".equals(internalName)) { + return "me/MyRunnable"; + } + return super.map(internalName); + } + }, + new SimpleRemapper( + /* latest */ Opcodes.ASM10_EXPERIMENTAL, + Map.of( + "java/lang/Runnable", "me/MyRunnable", + "java/lang/Runnable.run()V", "call"))); + } + + @SuppressWarnings("deprecation") + public static Stream remappersDeprecated() { + return Stream.of( + new Remapper() { + @Override + public String mapMethodName( + final String owner, final String name, final String descriptor) { + if ("java/lang/Runnable".equals(owner) && "run".equals(name)) { + return "call"; + } + return name; + } + + @Override + public String map(final String internalName) { + if ("java/lang/Runnable".equals(internalName)) { + return "me/MyRunnable"; + } + return super.map(internalName); + } + }, + new SimpleRemapper( + Map.of( + "java/lang/Runnable", "me/MyRunnable", + "java/lang/Runnable.run()V", "call"))); + } + + @Nested + @ParameterizedClass + @MethodSource("org.objectweb.asm.commons.LambdaRemapTest#remappersLatest") + class LatestApi { + + @Parameter Remapper remapper; + + @Test + void normalLambda() { + ClassNode classNode = new ClassNode(); + ClassRemapper classRemapper = + new ClassRemapper(/* latest api */ Opcodes.ASM9, classNode, remapper); + classRemapper.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null); + MethodVisitor methodVisitor = + classRemapper.visitMethod(Opcodes.ACC_PUBLIC, "hello", "()V", null, null); + methodVisitor.visitCode(); + + func_normalLambda(methodVisitor); + + InvokeDynamicInsnNode invokeDynamic = + (InvokeDynamicInsnNode) classNode.methods.get(0).instructions.get(0); + assertEquals("()Lme/MyRunnable;", invokeDynamic.desc); + assertEquals("call", invokeDynamic.name); + } + + @Test + void serializableLambda() { + ClassNode classNode = new ClassNode(); + ClassRemapper classRemapper = + new ClassRemapper(/* latest api */ Opcodes.ASM9, classNode, remapper); + classRemapper.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null); + MethodVisitor methodVisitor = + classRemapper.visitMethod(Opcodes.ACC_PUBLIC, "hello", "()V", null, null); + methodVisitor.visitCode(); + + func_serializableLambda(methodVisitor); + + InvokeDynamicInsnNode invokeDynamic = + (InvokeDynamicInsnNode) classNode.methods.get(0).instructions.get(0); + assertEquals("()Lme/MyRunnable;", invokeDynamic.desc); + assertEquals("call", invokeDynamic.name); + } + + @Test + void advancedLambda() { + ClassNode classNode = new ClassNode(); + ClassRemapper classRemapper = + new ClassRemapper(/* latest api */ Opcodes.ASM9, classNode, remapper); + classRemapper.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null); + MethodVisitor methodVisitor = + classRemapper.visitMethod(Opcodes.ACC_PUBLIC, "hello", "()V", null, null); + methodVisitor.visitCode(); + + func_advancedLambda(methodVisitor); + + InvokeDynamicInsnNode invokeDynamic = + (InvokeDynamicInsnNode) classNode.methods.get(0).instructions.get(0); + assertEquals("()Lme/MyRunnable;", invokeDynamic.desc); + assertEquals("call", invokeDynamic.name); + } + } + + @Nested + @ParameterizedClass + @MethodSource("org.objectweb.asm.commons.LambdaRemapTest#remappersDeprecated") + class DeprecatedApi { + @Parameter Remapper remapper; + + @Test + void normalLambda() { + ClassNode classNode = new ClassNode(); + ClassRemapper classRemapper = + new ClassRemapper(/* latest api */ Opcodes.ASM9, classNode, remapper); + classRemapper.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null); + MethodVisitor methodVisitor = + classRemapper.visitMethod(Opcodes.ACC_PUBLIC, "hello", "()V", null, null); + methodVisitor.visitCode(); + + func_normalLambda(methodVisitor); + + InvokeDynamicInsnNode invokeDynamic = + (InvokeDynamicInsnNode) classNode.methods.get(0).instructions.get(0); + assertEquals("()Lme/MyRunnable;", invokeDynamic.desc); + assertEquals("run", invokeDynamic.name); + } + + @Test + void serializableLambda() { + ClassNode classNode = new ClassNode(); + ClassRemapper classRemapper = + new ClassRemapper(/* latest api */ Opcodes.ASM9, classNode, remapper); + classRemapper.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null); + MethodVisitor methodVisitor = + classRemapper.visitMethod(Opcodes.ACC_PUBLIC, "hello", "()V", null, null); + methodVisitor.visitCode(); + + func_serializableLambda(methodVisitor); + + InvokeDynamicInsnNode invokeDynamic = + (InvokeDynamicInsnNode) classNode.methods.get(0).instructions.get(0); + assertEquals("()Lme/MyRunnable;", invokeDynamic.desc); + assertEquals("run", invokeDynamic.name); + } + + @Test + void advancedLambda() { + ClassNode classNode = new ClassNode(); + ClassRemapper classRemapper = + new ClassRemapper(/* latest api */ Opcodes.ASM9, classNode, remapper); + classRemapper.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null); + MethodVisitor methodVisitor = + classRemapper.visitMethod(Opcodes.ACC_PUBLIC, "hello", "()V", null, null); + methodVisitor.visitCode(); + + func_advancedLambda(methodVisitor); + + InvokeDynamicInsnNode invokeDynamic = + (InvokeDynamicInsnNode) classNode.methods.get(0).instructions.get(0); + assertEquals("()Lme/MyRunnable;", invokeDynamic.desc); + assertEquals("run", invokeDynamic.name); + } + } +} diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/LocalVariablesSorterTest.java b/asm-commons/src/test/java/org/objectweb/asm/commons/LocalVariablesSorterTest.java index 93bfb346..38095cf1 100644 --- a/asm-commons/src/test/java/org/objectweb/asm/commons/LocalVariablesSorterTest.java +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/LocalVariablesSorterTest.java @@ -32,7 +32,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; @@ -215,7 +214,7 @@ void testAllMethods_precompiledClass( } @Test - void testAllMethods_issue317586() throws FileNotFoundException, IOException { + void testAllMethods_issue317586() throws IOException { ClassReader classReader = new ClassReader(Files.newInputStream(Paths.get("src/test/resources/Issue317586.class"))); ClassWriter classWriter = new ClassWriter(0); diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/SimpleRemapperTest.java b/asm-commons/src/test/java/org/objectweb/asm/commons/SimpleRemapperTest.java index 50497e13..6e5f617f 100644 --- a/asm-commons/src/test/java/org/objectweb/asm/commons/SimpleRemapperTest.java +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/SimpleRemapperTest.java @@ -31,6 +31,7 @@ import java.util.Map; import org.junit.jupiter.api.Test; +import org.objectweb.asm.Opcodes; /** * Unit tests for {@link SimpleRemapper}. @@ -42,7 +43,9 @@ class SimpleRemapperTest { @Test void testMapSignature_remapParentOnly_nestedClassExtends() { String inputSignature = "LOuter.Inner;"; - Remapper remapper = new SimpleRemapper(Map.of("Outer", "RenamedOuter")); + Remapper remapper = + new SimpleRemapper( + /* latest */ Opcodes.ASM10_EXPERIMENTAL, Map.of("Outer", "RenamedOuter")); String remappedSignature = remapper.mapSignature(inputSignature, false); @@ -52,7 +55,9 @@ void testMapSignature_remapParentOnly_nestedClassExtends() { @Test void testMapSignature_remapChildOnly_nestedClassExtends() { String inputSignature = "LOuter.Inner;"; - Remapper remapper = new SimpleRemapper(Map.of("Outer$Inner", "Outer$RenamedInner")); + Remapper remapper = + new SimpleRemapper( + /* latest */ Opcodes.ASM10_EXPERIMENTAL, Map.of("Outer$Inner", "Outer$RenamedInner")); String remappedSignature = remapper.mapSignature(inputSignature, false); @@ -62,7 +67,10 @@ void testMapSignature_remapChildOnly_nestedClassExtends() { @Test void testMapSignature_remapChildOnly_nestedClassExtends_identifiersWithDollarSign() { String inputSignature = "LOuter.Inner$1;"; - Remapper remapper = new SimpleRemapper(Map.of("Outer$Inner$1", "Outer$RenamedInner$1")); + Remapper remapper = + new SimpleRemapper( + /* latest */ Opcodes.ASM10_EXPERIMENTAL, + Map.of("Outer$Inner$1", "Outer$RenamedInner$1")); String remappedSignature = remapper.mapSignature(inputSignature, false); @@ -74,7 +82,7 @@ void testMapSignature_remapBothParentAndChild_nestedClassExtends() { String inputSignature = "LOuter.Inner;"; Map mapping = Map.of("Outer", "RenamedOuter", "Outer$Inner", "RenamedOuter$RenamedInner"); - Remapper remapper = new SimpleRemapper(mapping); + Remapper remapper = new SimpleRemapper(/* latest */ Opcodes.ASM10_EXPERIMENTAL, mapping); String remappedSignature = remapper.mapSignature(inputSignature, false); diff --git a/asm-commons/src/test/java/org/objectweb/asm/commons/TryCatchBlockSorterTest.java b/asm-commons/src/test/java/org/objectweb/asm/commons/TryCatchBlockSorterTest.java index 5a92d245..871b4097 100644 --- a/asm-commons/src/test/java/org/objectweb/asm/commons/TryCatchBlockSorterTest.java +++ b/asm-commons/src/test/java/org/objectweb/asm/commons/TryCatchBlockSorterTest.java @@ -86,9 +86,9 @@ public MethodVisitor visitMethod( ClassFile classFile = new ClassFile(classWriter.toByteArray()); if (classParameter.isNotCompatibleWithCurrentJdk()) { - assertThrows(UnsupportedClassVersionError.class, () -> classFile.newInstance()); + assertThrows(UnsupportedClassVersionError.class, classFile::newInstance); } else { - assertDoesNotThrow(() -> classFile.newInstance()); + assertDoesNotThrow(classFile::newInstance); } } } diff --git a/asm-test/src/main/java/org/objectweb/asm/test/AsmTest.java b/asm-test/src/main/java/org/objectweb/asm/test/AsmTest.java index d9173774..4ddb93f9 100644 --- a/asm-test/src/main/java/org/objectweb/asm/test/AsmTest.java +++ b/asm-test/src/main/java/org/objectweb/asm/test/AsmTest.java @@ -154,6 +154,7 @@ public enum PrecompiledClass { JDK8_ALL_FRAMES("jdk8.AllFrames", JdkVersion.JDK8), JDK8_ALL_INSTRUCTIONS("jdk8.AllInstructions", JdkVersion.JDK8), JDK8_ALL_STRUCTURES("jdk8.AllStructures", JdkVersion.JDK8), + JDK8_ALL_LAMBDAS("jdk8.AllLambdas", JdkVersion.JDK8), JDK8_ANONYMOUS_INNER_CLASS("jdk8.AllStructures$1", JdkVersion.JDK8), JDK8_ARTIFICIAL_STRUCTURES("jdk8.Artificial$()$Structures", JdkVersion.JDK8), JDK8_INNER_CLASS("jdk8.AllStructures$InnerClass", JdkVersion.JDK8), diff --git a/asm-test/src/main/resources/jdk8/AllLambdas$InnerClass.class b/asm-test/src/main/resources/jdk8/AllLambdas$InnerClass.class new file mode 100644 index 00000000..81c62d84 Binary files /dev/null and b/asm-test/src/main/resources/jdk8/AllLambdas$InnerClass.class differ diff --git a/asm-test/src/main/resources/jdk8/AllLambdas.class b/asm-test/src/main/resources/jdk8/AllLambdas.class new file mode 100644 index 00000000..28a0f8e7 Binary files /dev/null and b/asm-test/src/main/resources/jdk8/AllLambdas.class differ diff --git a/asm-test/src/resources/java/jdk8/AllLambdas.java b/asm-test/src/resources/java/jdk8/AllLambdas.java new file mode 100644 index 00000000..fbc9cb5e --- /dev/null +++ b/asm-test/src/resources/java/jdk8/AllLambdas.java @@ -0,0 +1,54 @@ +// ASM: a very small and fast Java bytecode manipulation framework +// Copyright (c) 2000-2011 INRIA, France Telecom +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +package jdk8; + +import java.io.Serializable; + +public class AllLambdas { + public interface InnerClass { + default void inner() { + } + } + + public static void normalLambda() { + Runnable runnable = Thread::dumpStack; + } + + public static void advancedLambda() { + Runnable runnable = (Runnable & InnerClass) Thread::dumpStack; + } + + public static void serializableLambda() { + Runnable runnable = (Runnable & Serializable) Thread::dumpStack; + } + + public static void serializableAdvancedLambda() { + Runnable runnable = (Runnable & Serializable & InnerClass) Thread::dumpStack; + } +} + diff --git a/asm-test/src/test/java/org/objectweb/asm/test/ClassFileTest.java b/asm-test/src/test/java/org/objectweb/asm/test/ClassFileTest.java index e2e2a13b..ce7726ab 100644 --- a/asm-test/src/test/java/org/objectweb/asm/test/ClassFileTest.java +++ b/asm-test/src/test/java/org/objectweb/asm/test/ClassFileTest.java @@ -36,7 +36,7 @@ void testGetConstantPoolDump() { void testNewInstance_validClass(final PrecompiledClass classParameter, final Api apiParameter) { ClassFile classFile = new ClassFile(classParameter.getBytes()); - Executable newInstance = () -> classFile.newInstance(); + Executable newInstance = classFile::newInstance; if (classParameter.isNotCompatibleWithCurrentJdk()) { assertThrows(UnsupportedClassVersionError.class, newInstance); @@ -51,7 +51,7 @@ void testNewInstance_validClass(final PrecompiledClass classParameter, final Api void testNewInstance_invalidClass(final InvalidClass invalidClass) { ClassFile classFile = new ClassFile(invalidClass.getBytes()); - Executable newInstance = () -> classFile.newInstance(); + Executable newInstance = classFile::newInstance; assertThrows(ClassFormatException.class, newInstance); } @@ -123,7 +123,7 @@ void testHashcode_invalidClass() { InvalidClass invalidClass = InvalidClass.INVALID_CLASS_VERSION; ClassFile classFile = new ClassFile(invalidClass.getBytes()); - Executable hashCode = () -> classFile.hashCode(); + Executable hashCode = classFile::hashCode; Exception exception = assertThrows(ClassFormatException.class, hashCode); assertEquals("Unsupported class version", exception.getMessage()); @@ -144,7 +144,7 @@ void testToString_invalidClass() { InvalidClass invalidClass = InvalidClass.INVALID_CLASS_VERSION; ClassFile classFile = new ClassFile(invalidClass.getBytes()); - Executable toString = () -> classFile.toString(); + Executable toString = classFile::toString; Exception exception = assertThrows(ClassFormatException.class, toString); assertEquals("Unsupported class version", exception.getMessage()); diff --git a/asm-tree/src/main/java/org/objectweb/asm/tree/MethodNode.java b/asm-tree/src/main/java/org/objectweb/asm/tree/MethodNode.java index c5348534..5289c7db 100644 --- a/asm-tree/src/main/java/org/objectweb/asm/tree/MethodNode.java +++ b/asm-tree/src/main/java/org/objectweb/asm/tree/MethodNode.java @@ -611,6 +611,8 @@ public void check(final int api) { if (isInterface != (insn.opcode == Opcodes.INVOKEINTERFACE)) { throw new UnsupportedClassVersionException(); } + } else if (insn instanceof InvokeDynamicInsnNode) { + throw new UnsupportedClassVersionException(); } else if (insn instanceof LdcInsnNode) { Object value = ((LdcInsnNode) insn).cst; if (value instanceof Handle diff --git a/asm-tree/src/test/java/org/objectweb/asm/tree/ClassNodeTest.java b/asm-tree/src/test/java/org/objectweb/asm/tree/ClassNodeTest.java index e29f19bc..8b2534ed 100644 --- a/asm-tree/src/test/java/org/objectweb/asm/tree/ClassNodeTest.java +++ b/asm-tree/src/test/java/org/objectweb/asm/tree/ClassNodeTest.java @@ -195,13 +195,19 @@ public ModuleVisitor visitModule(final @DotSeparatedIdentifiers String name, fin } @Override - public void visitNestHost(final @InternalForm String nestHost) {} + public void visitNestHost(final String nestHost) { + // Remove nest host. + } @Override - public void visitNestMember(final @InternalForm String nestMember) {} + public void visitNestMember(final String nestMember) { + // Remove nest member. + } @Override - public void visitPermittedSubclass(final @InternalForm String permittedSubclass) {} + public void visitPermittedSubclass(final String permittedSubclass) { + // Remove permitted subclass. + } @Override public AnnotationVisitor visitAnnotation(final @FieldDescriptor String descriptor, final boolean visible) { @@ -218,7 +224,9 @@ public AnnotationVisitor visitTypeAnnotation( } @Override - public void visitAttribute(final Attribute attribute) {} + public void visitAttribute(final Attribute attribute) { + // Remove attribute. + } @Override public RecordComponentVisitor visitRecordComponent( diff --git a/asm-tree/src/test/java/org/objectweb/asm/tree/InsnListTest.java b/asm-tree/src/test/java/org/objectweb/asm/tree/InsnListTest.java index 93f033a0..76996e82 100644 --- a/asm-tree/src/test/java/org/objectweb/asm/tree/InsnListTest.java +++ b/asm-tree/src/test/java/org/objectweb/asm/tree/InsnListTest.java @@ -126,7 +126,7 @@ public void visitInsn(final int opcode) { void testIteratorNext_noSuchElement() { ListIterator iterator = newInsnList().iterator(); - Executable next = () -> iterator.next(); + Executable next = iterator::next; assertThrows(NoSuchElementException.class, next); } @@ -149,7 +149,7 @@ void testIteratorNext_nonEmptyList() { void testIteratorPrevious_noSuchElement() { ListIterator iterator = newInsnList().iterator(); - Executable previous = () -> iterator.previous(); + Executable previous = iterator::previous; assertThrows(NoSuchElementException.class, previous); } @@ -194,7 +194,7 @@ void testIteratorRemove_illegalState() { InsnList insnList = newInsnList(insn1, insn2); ListIterator iterator = insnList.iterator(1); - Executable remove = () -> iterator.remove(); + Executable remove = iterator::remove; assertThrows(IllegalStateException.class, remove); } diff --git a/asm-util/src/main/java/org/objectweb/asm/util/CheckMethodAdapter.java b/asm-util/src/main/java/org/objectweb/asm/util/CheckMethodAdapter.java index f62f4df4..f927ac79 100644 --- a/asm-util/src/main/java/org/objectweb/asm/util/CheckMethodAdapter.java +++ b/asm-util/src/main/java/org/objectweb/asm/util/CheckMethodAdapter.java @@ -295,6 +295,7 @@ private enum Method { private static final String MUST_NOT_BE_NULL_OR_EMPTY = " (must not be null or empty)"; private static final String START_LABEL = "start label"; private static final String END_LABEL = "end label"; + private static final String LABEL = "label"; /** The class version number. */ public int version; @@ -792,7 +793,7 @@ public void visitJumpInsn(final int opcode, final Label label) { checkVisitCodeCalled(); checkVisitMaxsNotCalled(); checkOpcodeMethod(opcode, Method.VISIT_JUMP_INSN); - checkLabel(label, /* checkVisited= */ false, "label"); + checkLabel(label, /* checkVisited= */ false, LABEL); super.visitJumpInsn(opcode, label); ++insnCount; } @@ -801,7 +802,7 @@ public void visitJumpInsn(final int opcode, final Label label) { public void visitLabel(final Label label) { checkVisitCodeCalled(); checkVisitMaxsNotCalled(); - checkLabel(label, /* checkVisited= */ false, "label"); + checkLabel(label, /* checkVisited= */ false, LABEL); if (labelInsnIndices.get(label) != null) { throw new IllegalStateException("Already visited label"); } @@ -1098,7 +1099,7 @@ private void checkFrameValue(final Object value) { if (value instanceof String) { checkInternalName(version, (@InternalForm String) value, "Invalid stack frame value"); } else if (value instanceof Label) { - checkLabel((Label) value, /* checkVisited= */ false, "label"); + checkLabel((Label) value, /* checkVisited= */ false, LABEL); } else { throw new IllegalArgumentException("Invalid stack frame value: " + value); } diff --git a/asm-util/src/main/java/org/objectweb/asm/util/Printer.java b/asm-util/src/main/java/org/objectweb/asm/util/Printer.java index ef485b42..fdb47b6c 100644 --- a/asm-util/src/main/java/org/objectweb/asm/util/Printer.java +++ b/asm-util/src/main/java/org/objectweb/asm/util/Printer.java @@ -960,7 +960,7 @@ public abstract void visitFrame( * @param descriptor the method's descriptor (see {@link Type}). * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead. */ - @Deprecated + @Deprecated(forRemoval = false) public void visitMethodInsn( final int opcode, final @InternalForm String owner, final @Identifier String name, final @MethodDescriptor String descriptor) { // This method was abstract before ASM5, and was therefore always overridden (without any diff --git a/asm-util/src/main/java/org/objectweb/asm/util/Textifier.java b/asm-util/src/main/java/org/objectweb/asm/util/Textifier.java index dd28930d..90437bab 100644 --- a/asm-util/src/main/java/org/objectweb/asm/util/Textifier.java +++ b/asm-util/src/main/java/org/objectweb/asm/util/Textifier.java @@ -328,7 +328,7 @@ public void visitInnerClass( final @InternalForm String name, final @InternalForm String outerName, final @Identifier String innerName, final int access) { stringBuilder.setLength(0); stringBuilder.append(tab); - appendRawAccess(access & ~Opcodes.ACC_SUPER); + appendRawAccess(access); stringBuilder.append(tab); appendAccess(access); stringBuilder.append("INNERCLASS "); @@ -1449,7 +1449,13 @@ protected void appendLabel(final Label label) { stringBuilder.append(name); } - @Deprecated + /** + * Appends a string representation of the given handle to {@link #stringBuilder}. + * + * @param handle a handle. + * @deprecated use {@link #appendHandle(Handle, String)} instead. + */ + @Deprecated(forRemoval = false) protected void appendHandle(final Handle handle) { appendHandle(handle, tab3); } diff --git a/asm-util/src/test/java/org/objectweb/asm/util/CheckClassAdapterTest.java b/asm-util/src/test/java/org/objectweb/asm/util/CheckClassAdapterTest.java index 3b00a498..e9b2a3b4 100644 --- a/asm-util/src/test/java/org/objectweb/asm/util/CheckClassAdapterTest.java +++ b/asm-util/src/test/java/org/objectweb/asm/util/CheckClassAdapterTest.java @@ -380,7 +380,7 @@ void testVisitMethod_checkDataFlowByDefault() { methodVisitor.visitInsn(IRETURN); methodVisitor.visitMaxs(0, 0); - Executable visitEnd = () -> methodVisitor.visitEnd(); + Executable visitEnd = methodVisitor::visitEnd; Exception exception = assertThrows(IllegalArgumentException.class, visitEnd); assertTrue( @@ -403,7 +403,7 @@ void testVisitMethod_checkMaxStackAndLocalsIfClassWriterWithoutComputeMaxs() { methodVisitor.visitInsn(IRETURN); methodVisitor.visitMaxs(0, 2); - Executable visitEnd = () -> methodVisitor.visitEnd(); + Executable visitEnd = methodVisitor::visitEnd; Exception exception = assertThrows(IllegalArgumentException.class, visitEnd); assertTrue( @@ -423,7 +423,7 @@ void testVisitMethod_noDataFlowCheckIfDisabled() { methodVisitor.visitInsn(IRETURN); methodVisitor.visitMaxs(0, 0); - Executable visitEnd = () -> methodVisitor.visitEnd(); + Executable visitEnd = methodVisitor::visitEnd; assertDoesNotThrow(visitEnd); } diff --git a/asm-util/src/test/java/org/objectweb/asm/util/CheckMethodAdapterTest.java b/asm-util/src/test/java/org/objectweb/asm/util/CheckMethodAdapterTest.java index 37567c0c..c923f483 100644 --- a/asm-util/src/test/java/org/objectweb/asm/util/CheckMethodAdapterTest.java +++ b/asm-util/src/test/java/org/objectweb/asm/util/CheckMethodAdapterTest.java @@ -125,7 +125,7 @@ void testVisitCode_abstractMethod() { CheckMethodAdapter checkAbstractMethodAdapter = new CheckMethodAdapter(Opcodes.ACC_ABSTRACT, "m", "()V", null, Map.of()); - Executable visitCode = () -> checkAbstractMethodAdapter.visitCode(); + Executable visitCode = checkAbstractMethodAdapter::visitCode; Exception exception = assertThrows(UnsupportedOperationException.class, visitCode); assertEquals("Abstract methods cannot have code", exception.getMessage()); @@ -1109,7 +1109,7 @@ void testVisitEnd_invalidDataFlow() { dataFlowCheckMethodAdapter.visitInsn(IRETURN); dataFlowCheckMethodAdapter.visitMaxs(0, 0); - Executable visitEnd = () -> dataFlowCheckMethodAdapter.visitEnd(); + Executable visitEnd = dataFlowCheckMethodAdapter::visitEnd; Exception exception = assertThrows(IllegalArgumentException.class, visitEnd); assertTrue( @@ -1136,7 +1136,7 @@ void testVisitEnd_noInvalidMaxStackIfClassWriterWithComputeMaxs() { dataFlowCheckMethodAdapter.visitInsn(IRETURN); dataFlowCheckMethodAdapter.visitMaxs(0, 2); - Executable visitEnd = () -> dataFlowCheckMethodAdapter.visitEnd(); + Executable visitEnd = dataFlowCheckMethodAdapter::visitEnd; assertDoesNotThrow(visitEnd); } @@ -1157,7 +1157,7 @@ void testVisitEnd_noInvalidMaxStackIfClassWriterWithComputeFrames() { dataFlowCheckMethodAdapter.visitInsn(IRETURN); dataFlowCheckMethodAdapter.visitMaxs(0, 2); - Executable visitEnd = () -> dataFlowCheckMethodAdapter.visitEnd(); + Executable visitEnd = dataFlowCheckMethodAdapter::visitEnd; assertDoesNotThrow(visitEnd); } @@ -1178,7 +1178,7 @@ void testVisitEnd_invalidMaxStackIfClassWriterWithoutComputeMaxsOrComputeFrames( dataFlowCheckMethodAdapter.visitInsn(IRETURN); dataFlowCheckMethodAdapter.visitMaxs(0, 2); - Executable visitEnd = () -> dataFlowCheckMethodAdapter.visitEnd(); + Executable visitEnd = dataFlowCheckMethodAdapter::visitEnd; Exception exception = assertThrows(IllegalArgumentException.class, visitEnd); assertTrue( @@ -1207,7 +1207,7 @@ void testVisitEnd_noMissingFrameIfClassWriterWithComputeFrames() { dataFlowCheckMethodAdapter.visitInsn(IRETURN); dataFlowCheckMethodAdapter.visitMaxs(1, 2); - Executable visitEnd = () -> dataFlowCheckMethodAdapter.visitEnd(); + Executable visitEnd = dataFlowCheckMethodAdapter::visitEnd; assertDoesNotThrow(visitEnd); } @@ -1232,7 +1232,7 @@ void testVisitEnd_missingFrameIfClassWriterWithoutComputeFrames() { dataFlowCheckMethodAdapter.visitInsn(IRETURN); dataFlowCheckMethodAdapter.visitMaxs(1, 2); - Executable visitEnd = () -> dataFlowCheckMethodAdapter.visitEnd(); + Executable visitEnd = dataFlowCheckMethodAdapter::visitEnd; Exception exception = assertThrows(IllegalArgumentException.class, visitEnd); assertTrue( @@ -1250,7 +1250,7 @@ void testVisitEnd_invalidReturnType() { dataFlowCheckMethodAdapter.visitInsn(IRETURN); dataFlowCheckMethodAdapter.visitMaxs(1, 2); - Executable visitEnd = () -> dataFlowCheckMethodAdapter.visitEnd(); + Executable visitEnd = dataFlowCheckMethodAdapter::visitEnd; Exception exception = assertThrows(IllegalArgumentException.class, visitEnd); assertTrue( diff --git a/asm-util/src/test/java/org/objectweb/asm/util/CheckSignatureAdapterTest.java b/asm-util/src/test/java/org/objectweb/asm/util/CheckSignatureAdapterTest.java index 95cb8e8c..518ae783 100644 --- a/asm-util/src/test/java/org/objectweb/asm/util/CheckSignatureAdapterTest.java +++ b/asm-util/src/test/java/org/objectweb/asm/util/CheckSignatureAdapterTest.java @@ -73,7 +73,7 @@ void testVisitClassBound_classSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, null); - Executable visitClassBound = () -> checkSignatureAdapter.visitClassBound(); + Executable visitClassBound = checkSignatureAdapter::visitClassBound; assertThrows(IllegalStateException.class, visitClassBound); } @@ -83,7 +83,7 @@ void testVisitClassBound_typeSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.TYPE_SIGNATURE, null); - Executable visitClassBound = () -> checkSignatureAdapter.visitClassBound(); + Executable visitClassBound = checkSignatureAdapter::visitClassBound; assertThrows(IllegalStateException.class, visitClassBound); } @@ -93,7 +93,7 @@ void testVisitInterfaceBound_classSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, null); - Executable visitInterfaceBound = () -> checkSignatureAdapter.visitInterfaceBound(); + Executable visitInterfaceBound = checkSignatureAdapter::visitInterfaceBound; assertThrows(IllegalStateException.class, visitInterfaceBound); } @@ -103,7 +103,7 @@ void testVisitInterfaceBound_typeSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.TYPE_SIGNATURE, null); - Executable visitInterfaceBound = () -> checkSignatureAdapter.visitInterfaceBound(); + Executable visitInterfaceBound = checkSignatureAdapter::visitInterfaceBound; assertThrows(IllegalStateException.class, visitInterfaceBound); } @@ -114,7 +114,7 @@ void testVisitSuperClass_classSignature_illegalState() { new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, null); checkSignatureAdapter.visitSuperclass(); - Executable visitSuperClass = () -> checkSignatureAdapter.visitSuperclass(); + Executable visitSuperClass = checkSignatureAdapter::visitSuperclass; assertThrows(IllegalStateException.class, visitSuperClass); } @@ -124,7 +124,7 @@ void testVisitSuperClass_methodSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.METHOD_SIGNATURE, null); - Executable visitSuperClass = () -> checkSignatureAdapter.visitSuperclass(); + Executable visitSuperClass = checkSignatureAdapter::visitSuperclass; assertThrows(IllegalStateException.class, visitSuperClass); } @@ -134,7 +134,7 @@ void testVisitInterface_classSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, null); - Executable visitInterface = () -> checkSignatureAdapter.visitInterface(); + Executable visitInterface = checkSignatureAdapter::visitInterface; assertThrows(IllegalStateException.class, visitInterface); } @@ -144,7 +144,7 @@ void testVisitInterface_methodSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.METHOD_SIGNATURE, null); - Executable visitInterface = () -> checkSignatureAdapter.visitInterface(); + Executable visitInterface = checkSignatureAdapter::visitInterface; assertThrows(IllegalStateException.class, visitInterface); } @@ -154,7 +154,7 @@ void testVisitParameterType_classSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, null); - Executable visitParameterType = () -> checkSignatureAdapter.visitParameterType(); + Executable visitParameterType = checkSignatureAdapter::visitParameterType; assertThrows(IllegalStateException.class, visitParameterType); } @@ -165,7 +165,7 @@ void testVisitParameterType_methodSignature_illegalState() { new CheckSignatureAdapter(CheckSignatureAdapter.METHOD_SIGNATURE, null); checkSignatureAdapter.visitReturnType(); - Executable visitParameterType = () -> checkSignatureAdapter.visitParameterType(); + Executable visitParameterType = checkSignatureAdapter::visitParameterType; assertThrows(IllegalStateException.class, visitParameterType); } @@ -175,7 +175,7 @@ void testVisitReturnType_classSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, null); - Executable visitReturnType = () -> checkSignatureAdapter.visitReturnType(); + Executable visitReturnType = checkSignatureAdapter::visitReturnType; assertThrows(IllegalStateException.class, visitReturnType); } @@ -186,7 +186,7 @@ void testVisitReturnType_methodSignature_illegalState() { new CheckSignatureAdapter(CheckSignatureAdapter.METHOD_SIGNATURE, null); checkSignatureAdapter.visitReturnType(); - Executable visitReturnType = () -> checkSignatureAdapter.visitReturnType(); + Executable visitReturnType = checkSignatureAdapter::visitReturnType; assertThrows(IllegalStateException.class, visitReturnType); } @@ -196,7 +196,7 @@ void testVisitExceptionType_classSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, null); - Executable visitExceptionType = () -> checkSignatureAdapter.visitExceptionType(); + Executable visitExceptionType = checkSignatureAdapter::visitExceptionType; assertThrows(IllegalStateException.class, visitExceptionType); } @@ -206,7 +206,7 @@ void testVisitExceptionType_methodSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.METHOD_SIGNATURE, null); - Executable visitExceptionType = () -> checkSignatureAdapter.visitExceptionType(); + Executable visitExceptionType = checkSignatureAdapter::visitExceptionType; assertThrows(IllegalStateException.class, visitExceptionType); } @@ -314,7 +314,7 @@ void testVisitArrayType_classSignature_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, null); - Executable visitArrayType = () -> checkSignatureAdapter.visitArrayType(); + Executable visitArrayType = checkSignatureAdapter::visitArrayType; assertThrows(IllegalStateException.class, visitArrayType); } @@ -325,7 +325,7 @@ void testVisitArrayType_typeSignature_illegalState() { new CheckSignatureAdapter(CheckSignatureAdapter.TYPE_SIGNATURE, null); checkSignatureAdapter.visitArrayType(); - Executable visitArrayType = () -> checkSignatureAdapter.visitArrayType(); + Executable visitArrayType = checkSignatureAdapter::visitArrayType; assertThrows(IllegalStateException.class, visitArrayType); } @@ -411,7 +411,7 @@ void testVisitTypeArgument_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.TYPE_SIGNATURE, null); - Executable visitTypeArgument = () -> checkSignatureAdapter.visitTypeArgument(); + Executable visitTypeArgument = checkSignatureAdapter::visitTypeArgument; assertThrows(IllegalStateException.class, visitTypeArgument); } @@ -443,7 +443,7 @@ void testVisitEnd_illegalState() { CheckSignatureAdapter checkSignatureAdapter = new CheckSignatureAdapter(CheckSignatureAdapter.TYPE_SIGNATURE, null); - Executable visitEnd = () -> checkSignatureAdapter.visitEnd(); + Executable visitEnd = checkSignatureAdapter::visitEnd; assertThrows(IllegalStateException.class, visitEnd); } diff --git a/asm-util/src/test/java/org/objectweb/asm/util/CodeComment.java b/asm-util/src/test/java/org/objectweb/asm/util/CodeComment.java index 86ffe56c..9ba043de 100644 --- a/asm-util/src/test/java/org/objectweb/asm/util/CodeComment.java +++ b/asm-util/src/test/java/org/objectweb/asm/util/CodeComment.java @@ -88,5 +88,7 @@ public void asmify( } @Override - public void textify(final StringBuilder stringBuilder, final Map labelNames) {} + public void textify(final StringBuilder stringBuilder, final Map labelNames) { + stringBuilder.append("(empty)"); + } } diff --git a/asm-util/src/test/java/org/objectweb/asm/util/Comment.java b/asm-util/src/test/java/org/objectweb/asm/util/Comment.java index 31bbb2c6..1b9b3baf 100644 --- a/asm-util/src/test/java/org/objectweb/asm/util/Comment.java +++ b/asm-util/src/test/java/org/objectweb/asm/util/Comment.java @@ -83,7 +83,9 @@ public void asmify( } @Override - public void textify(final StringBuilder stringBuilder, final Map labelNames) {} + public void textify(final StringBuilder stringBuilder, final Map labelNames) { + stringBuilder.append("(empty)"); + } @Override public String toString() { diff --git a/asm-util/src/test/java/org/objectweb/asm/util/PrinterTest.java b/asm-util/src/test/java/org/objectweb/asm/util/PrinterTest.java index ff0d22aa..0e406c06 100644 --- a/asm-util/src/test/java/org/objectweb/asm/util/PrinterTest.java +++ b/asm-util/src/test/java/org/objectweb/asm/util/PrinterTest.java @@ -172,7 +172,7 @@ void testVisitProvide_unsupportedByDefault() { void testVisitModuleEnd_unsupportedByDefault() { Printer printer = new EmptyPrinter(/* latest */ Opcodes.ASM10_EXPERIMENTAL); - Executable visitModuleEnd = () -> printer.visitModuleEnd(); + Executable visitModuleEnd = printer::visitModuleEnd; Exception exception = assertThrows(UnsupportedOperationException.class, visitModuleEnd); assertEquals(UNSUPPORTED_OPERATION_MESSAGE, exception.getMessage()); diff --git a/asm-util/src/test/java/org/objectweb/asm/util/SignaturesProviders.java b/asm-util/src/test/java/org/objectweb/asm/util/SignaturesProviders.java index 44e55de1..b2c2ad2d 100644 --- a/asm-util/src/test/java/org/objectweb/asm/util/SignaturesProviders.java +++ b/asm-util/src/test/java/org/objectweb/asm/util/SignaturesProviders.java @@ -28,7 +28,7 @@ public final class SignaturesProviders { AsmTest.allClassesAndLatestApi() .map(argument -> (PrecompiledClass) argument.get()[0]) .filter(precompiledClass -> !precompiledClass.isMoreRecentThan(AsmTest.Api.ASM7)) - .forEach(precompiledClass -> collectSignatures(precompiledClass)); + .forEach(SignaturesProviders::collectSignatures); assertFalse(CLASS_SIGNATURES.isEmpty()); assertFalse(FIELD_SIGNATURES.isEmpty()); assertFalse(METHOD_SIGNATURES.isEmpty()); diff --git a/asm-util/src/test/resources/jdk8.AllLambdas.txt b/asm-util/src/test/resources/jdk8.AllLambdas.txt new file mode 100644 index 00000000..bf41b2d7 --- /dev/null +++ b/asm-util/src/test/resources/jdk8.AllLambdas.txt @@ -0,0 +1,243 @@ +// class version 52.0 (52) +// access flags 0x21 +public class jdk8/AllLambdas { + + // compiled from: AllLambdas.java + // access flags 0x609 + public static abstract INNERCLASS jdk8/AllLambdas$InnerClass jdk8/AllLambdas InnerClass + // access flags 0x19 + public final static INNERCLASS java/lang/invoke/MethodHandles$Lookup java/lang/invoke/MethodHandles Lookup + + // access flags 0x1 + public ()V + L0 + LINENUMBER 32 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x9 + public static normalLambda()V + L0 + LINENUMBER 39 L0 + INVOKEDYNAMIC run()Ljava/lang/Runnable; [ + // handle kind 0x6 : INVOKESTATIC + java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; + // arguments: + ()V, + // handle kind 0x6 : INVOKESTATIC + java/lang/Thread.dumpStack()V, + ()V + ] + ASTORE 0 + L1 + LINENUMBER 40 L1 + RETURN + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x9 + public static advancedLambda()V + L0 + LINENUMBER 43 L0 + INVOKEDYNAMIC run()Ljava/lang/Runnable; [ + // handle kind 0x6 : INVOKESTATIC + java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; + // arguments: + ()V, + // handle kind 0x6 : INVOKESTATIC + java/lang/Thread.dumpStack()V, + ()V, + 6, + 1, + jdk8.AllLambdas$InnerClass.class, + 0 + ] + CHECKCAST jdk8/AllLambdas$InnerClass + CHECKCAST java/lang/Runnable + ASTORE 0 + L1 + LINENUMBER 44 L1 + RETURN + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x9 + public static serializableLambda()V + L0 + LINENUMBER 47 L0 + INVOKEDYNAMIC run()Ljava/lang/Runnable; [ + // handle kind 0x6 : INVOKESTATIC + java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; + // arguments: + ()V, + // handle kind 0x6 : INVOKESTATIC + java/lang/Thread.dumpStack()V, + ()V, + 5, + 0 + ] + CHECKCAST java/io/Serializable + CHECKCAST java/lang/Runnable + ASTORE 0 + L1 + LINENUMBER 48 L1 + RETURN + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x9 + public static serializableAdvancedLambda()V + L0 + LINENUMBER 51 L0 + INVOKEDYNAMIC run()Ljava/lang/Runnable; [ + // handle kind 0x6 : INVOKESTATIC + java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; + // arguments: + ()V, + // handle kind 0x6 : INVOKESTATIC + java/lang/Thread.dumpStack()V, + ()V, + 7, + 1, + jdk8.AllLambdas$InnerClass.class, + 0 + ] + CHECKCAST java/io/Serializable + CHECKCAST jdk8/AllLambdas$InnerClass + CHECKCAST java/lang/Runnable + ASTORE 0 + L1 + LINENUMBER 52 L1 + RETURN + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x100A + private static synthetic $deserializeLambda$(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object; + L0 + LINENUMBER 32 L0 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getImplMethodName ()Ljava/lang/String; + ASTORE 1 + ICONST_M1 + ISTORE 2 + ALOAD 1 + INVOKEVIRTUAL java/lang/String.hashCode ()I + LOOKUPSWITCH + -1366118156: L1 + default: L2 + L1 + FRAME APPEND [java/lang/String I] + ALOAD 1 + LDC "dumpStack" + INVOKEVIRTUAL java/lang/String.equals (Ljava/lang/Object;)Z + IFEQ L2 + ICONST_0 + ISTORE 2 + L2 + FRAME SAME + ILOAD 2 + LOOKUPSWITCH + 0: L3 + default: L4 + L3 + FRAME SAME + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getImplMethodKind ()I + BIPUSH 6 + IF_ICMPNE L5 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getFunctionalInterfaceClass ()Ljava/lang/String; + LDC "java/lang/Runnable" + INVOKEVIRTUAL java/lang/Object.equals (Ljava/lang/Object;)Z + IFEQ L5 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getFunctionalInterfaceMethodName ()Ljava/lang/String; + LDC "run" + INVOKEVIRTUAL java/lang/Object.equals (Ljava/lang/Object;)Z + IFEQ L5 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getFunctionalInterfaceMethodSignature ()Ljava/lang/String; + LDC "()V" + INVOKEVIRTUAL java/lang/Object.equals (Ljava/lang/Object;)Z + IFEQ L5 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getImplClass ()Ljava/lang/String; + LDC "java/lang/Thread" + INVOKEVIRTUAL java/lang/Object.equals (Ljava/lang/Object;)Z + IFEQ L5 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getImplMethodSignature ()Ljava/lang/String; + LDC "()V" + INVOKEVIRTUAL java/lang/Object.equals (Ljava/lang/Object;)Z + IFEQ L5 + INVOKEDYNAMIC run()Ljava/lang/Runnable; [ + // handle kind 0x6 : INVOKESTATIC + java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; + // arguments: + ()V, + // handle kind 0x6 : INVOKESTATIC + java/lang/Thread.dumpStack()V, + ()V, + 5, + 0 + ] + ARETURN + L5 + FRAME SAME + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getImplMethodKind ()I + BIPUSH 6 + IF_ICMPNE L4 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getFunctionalInterfaceClass ()Ljava/lang/String; + LDC "java/lang/Runnable" + INVOKEVIRTUAL java/lang/Object.equals (Ljava/lang/Object;)Z + IFEQ L4 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getFunctionalInterfaceMethodName ()Ljava/lang/String; + LDC "run" + INVOKEVIRTUAL java/lang/Object.equals (Ljava/lang/Object;)Z + IFEQ L4 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getFunctionalInterfaceMethodSignature ()Ljava/lang/String; + LDC "()V" + INVOKEVIRTUAL java/lang/Object.equals (Ljava/lang/Object;)Z + IFEQ L4 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getImplClass ()Ljava/lang/String; + LDC "java/lang/Thread" + INVOKEVIRTUAL java/lang/Object.equals (Ljava/lang/Object;)Z + IFEQ L4 + ALOAD 0 + INVOKEVIRTUAL java/lang/invoke/SerializedLambda.getImplMethodSignature ()Ljava/lang/String; + LDC "()V" + INVOKEVIRTUAL java/lang/Object.equals (Ljava/lang/Object;)Z + IFEQ L4 + INVOKEDYNAMIC run()Ljava/lang/Runnable; [ + // handle kind 0x6 : INVOKESTATIC + java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; + // arguments: + ()V, + // handle kind 0x6 : INVOKESTATIC + java/lang/Thread.dumpStack()V, + ()V, + 7, + 1, + jdk8.AllLambdas$InnerClass.class, + 0 + ] + ARETURN + L4 + FRAME SAME + NEW java/lang/IllegalArgumentException + DUP + LDC "Invalid lambda deserialization" + INVOKESPECIAL java/lang/IllegalArgumentException. (Ljava/lang/String;)V + ATHROW + MAXSTACK = 3 + MAXLOCALS = 3 +} diff --git a/asm/src/main/java/org/objectweb/asm/Attribute.java b/asm/src/main/java/org/objectweb/asm/Attribute.java index aa34a57c..5c42c77c 100644 --- a/asm/src/main/java/org/objectweb/asm/Attribute.java +++ b/asm/src/main/java/org/objectweb/asm/Attribute.java @@ -95,7 +95,7 @@ public boolean isCodeAttribute() { * a Code attribute that contains labels. * @deprecated no longer used by ASM. */ - @Deprecated + @Deprecated(forRemoval = false) protected Label[] getLabels() { return new Label[0]; } @@ -174,6 +174,7 @@ public static Attribute read( * ClassReader overrides {@link ClassReader#readLabel}. Hence {@link #read(ClassReader, int, int, * char[], int, Label[])} must not manually create {@link Label} instances. * + * @param classReader the class that contains the attribute to be read. * @param bytecodeOffset a bytecode offset in a method. * @param labels the already created labels, indexed by their offset. If a label already exists * for bytecodeOffset this method does not create a new one. Otherwise it stores the new label diff --git a/asm/src/main/java/org/objectweb/asm/ClassReader.java b/asm/src/main/java/org/objectweb/asm/ClassReader.java index 0b4aba20..e2f6039f 100644 --- a/asm/src/main/java/org/objectweb/asm/ClassReader.java +++ b/asm/src/main/java/org/objectweb/asm/ClassReader.java @@ -106,7 +106,7 @@ public class ClassReader { * @deprecated Use {@link #readByte(int)} and the other read methods instead. This field will * eventually be deleted. */ - @Deprecated + @Deprecated(forRemoval = false) // DontCheck(MemberName): can't be renamed (for backward binary compatibility). public final byte[] b; @@ -3545,6 +3545,9 @@ private Attribute readAttribute( final char[] charBuffer, final int codeAttributeOffset, final Label[] labels) { + if (length > classFileBuffer.length - offset) { + throw new IllegalArgumentException(); + } for (Attribute attributePrototype : attributePrototypes) { if (attributePrototype.type.equals(type)) { return attributePrototype.read( diff --git a/asm/src/main/java/org/objectweb/asm/ClassWriter.java b/asm/src/main/java/org/objectweb/asm/ClassWriter.java index 8194b61e..f6d2d5ac 100644 --- a/asm/src/main/java/org/objectweb/asm/ClassWriter.java +++ b/asm/src/main/java/org/objectweb/asm/ClassWriter.java @@ -906,7 +906,7 @@ public int newPackage(final @DotSeparatedIdentifiers String packageName) { * @deprecated this method is superseded by {@link #newHandle(int, String, String, String, * boolean)}. */ - @Deprecated + @Deprecated(forRemoval = false) public int newHandle( final int tag, final @InternalForm String owner, final String name, final String descriptor) { return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); diff --git a/asm/src/main/java/org/objectweb/asm/Handle.java b/asm/src/main/java/org/objectweb/asm/Handle.java index d94bdd72..34983fc2 100644 --- a/asm/src/main/java/org/objectweb/asm/Handle.java +++ b/asm/src/main/java/org/objectweb/asm/Handle.java @@ -73,8 +73,8 @@ public final class Handle { * @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String, * boolean)}. */ - @Deprecated - public Handle(final int tag, final @InternalForm String owner, final String name, final String descriptor) { + @Deprecated(forRemoval = false) + public Handle(final int tag, final String owner, final String name, final String descriptor) { this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); } diff --git a/asm/src/main/java/org/objectweb/asm/MethodVisitor.java b/asm/src/main/java/org/objectweb/asm/MethodVisitor.java index 665eab68..bfa74452 100644 --- a/asm/src/main/java/org/objectweb/asm/MethodVisitor.java +++ b/asm/src/main/java/org/objectweb/asm/MethodVisitor.java @@ -421,7 +421,7 @@ public void visitFieldInsn( * @param descriptor the method's descriptor (see {@link Type}). * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead. */ - @Deprecated + @Deprecated(forRemoval = false) public void visitMethodInsn( final int opcode, final @InternalForm String owner, final @Identifier String name, final @MethodDescriptor String descriptor) { int opcodeAndSource = opcode | (api < Opcodes.ASM5 ? Opcodes.SOURCE_DEPRECATED : 0); diff --git a/asm/src/main/java/org/objectweb/asm/ModuleVisitor.java b/asm/src/main/java/org/objectweb/asm/ModuleVisitor.java index 68af6ae0..71687ae0 100644 --- a/asm/src/main/java/org/objectweb/asm/ModuleVisitor.java +++ b/asm/src/main/java/org/objectweb/asm/ModuleVisitor.java @@ -96,7 +96,7 @@ public ModuleVisitor getDelegate() { } /** - * Visit the main class of the current module. + * Visits the main class of the current module. * * @param mainClass the internal name of the main class of the current module (see {@link * Type#getInternalName()}). @@ -108,7 +108,7 @@ public void visitMainClass(final @InternalForm String mainClass) { } /** - * Visit a package of the current module. + * Visits a package of the current module. * * @param packaze the internal name of a package (see {@link Type#getInternalName()}). */ @@ -133,7 +133,7 @@ public void visitRequire(final @DotSeparatedIdentifiers String module, final int } /** - * Visit an exported package of the current module. + * Visits an exported package of the current module. * * @param packaze the internal name of the exported package (see {@link Type#getInternalName()}). * @param access the access flag of the exported package, valid values are among {@code @@ -148,7 +148,7 @@ public void visitExport(final @DotSeparatedIdentifiers String packaze, final int } /** - * Visit an open package of the current module. + * Visits an open package of the current module. * * @param packaze the internal name of the opened package (see {@link Type#getInternalName()}). * @param access the access flag of the opened package, valid values are among {@code @@ -163,7 +163,7 @@ public void visitOpen(final @DotSeparatedIdentifiers String packaze, final int a } /** - * Visit a service used by the current module. The name must be the internal name of an interface + * Visits a service used by the current module. The name must be the internal name of an interface * or a class. * * @param service the internal name of the service (see {@link Type#getInternalName()}). @@ -175,7 +175,7 @@ public void visitUse(final @InternalForm String service) { } /** - * Visit an implementation of a service. + * Visits an implementation of a service. * * @param service the internal name of the service (see {@link Type#getInternalName()}). * @param providers the internal names (see {@link Type#getInternalName()}) of the implementations diff --git a/asm/src/main/java/org/objectweb/asm/Opcodes.java b/asm/src/main/java/org/objectweb/asm/Opcodes.java index 26074555..7a118114 100644 --- a/asm/src/main/java/org/objectweb/asm/Opcodes.java +++ b/asm/src/main/java/org/objectweb/asm/Opcodes.java @@ -56,7 +56,8 @@ public interface Opcodes { * * @deprecated This API is experimental. */ - @Deprecated int ASM10_EXPERIMENTAL = 1 << 24 | 10 << 16 | 0 << 8; + @Deprecated(forRemoval = false) + int ASM10_EXPERIMENTAL = 1 << 24 | 10 << 16 | 0 << 8; /* * Internal flags used to redirect calls to deprecated methods. For instance, if a visitOldStuff @@ -292,6 +293,12 @@ public interface Opcodes { int V24 = 0 << 16 | 68; int V25 = 0 << 16 | 69; int V26 = 0 << 16 | 70; + int V27 = 0 << 16 | 71; + int V28 = 0 << 16 | 72; + int V29 = 0 << 16 | 73; + int V30 = 0 << 16 | 74; + int V31 = 0 << 16 | 75; + /** * Version flag indicating that the class is using 'preview' features. * diff --git a/asm/src/main/java/org/objectweb/asm/SymbolTable.java b/asm/src/main/java/org/objectweb/asm/SymbolTable.java index 99f6b68c..e7ade340 100644 --- a/asm/src/main/java/org/objectweb/asm/SymbolTable.java +++ b/asm/src/main/java/org/objectweb/asm/SymbolTable.java @@ -1479,7 +1479,7 @@ private static final class LabelEntry { /** * Another entry (and so on recursively) having the same hash code (modulo the size of {@link - * SymbolTable#labelEntries}}) as this one. + * SymbolTable#labelEntries}) as this one. */ LabelEntry next; diff --git a/asm/src/test/java/org/objectweb/asm/ClassReaderTest.java b/asm/src/test/java/org/objectweb/asm/ClassReaderTest.java index 98fc4bca..9120ecde 100644 --- a/asm/src/test/java/org/objectweb/asm/ClassReaderTest.java +++ b/asm/src/test/java/org/objectweb/asm/ClassReaderTest.java @@ -41,6 +41,7 @@ import java.io.IOException; import java.io.InputStream; import java.time.Duration; +import java.util.Base64; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -351,9 +352,10 @@ void testAccept_emptyVisitor_skipCode( // jdk8.ArtificialStructures contains structures which require ASM5, but only inside the method // code. Here we skip the code, so this class can be read with ASM4. Likewise for - // jdk11.AllInstructions. + // jdk8.AllLambdas and jdk11.AllInstructions. if (classParameter.isMoreRecentThan(apiParameter) && classParameter != PrecompiledClass.JDK8_ARTIFICIAL_STRUCTURES + && classParameter != PrecompiledClass.JDK8_ALL_LAMBDAS && classParameter != PrecompiledClass.JDK11_ALL_INSTRUCTIONS) { Exception exception = assertThrows(UnsupportedOperationException.class, accept); assertTrue(exception.getMessage().matches(UNSUPPORTED_OPERATION_MESSAGE_PATTERN)); @@ -417,13 +419,19 @@ public MethodVisitor visitMethod( } @Override - public void visitNestHost(final @InternalForm String nestHost) {} + public void visitNestHost(final String nestHost) { + // Skip nest host. + } @Override - public void visitNestMember(final @InternalForm String nestMember) {} + public void visitNestMember(final String nestMember) { + // Skip nest member. + } @Override - public void visitPermittedSubclass(final @InternalForm String permittedSubclass) {} + public void visitPermittedSubclass(final String permittedSubclass) { + // Skip permitted subclass. + } }; Executable accept = () -> classReader.accept(classVisitor, 0); @@ -629,6 +637,17 @@ public void visit( assertEquals(Opcodes.V_PREVIEW, classVersion.get() & Opcodes.V_PREVIEW); } + @Test + void testAccept_invalidCustomAttribute() { + byte[] input = Base64.getDecoder().decode("IftdBAAAAAAAAgEAAAD/AAAAAAAAAAAAAAIBAAF/////"); + ClassReader reader = new ClassReader(input); + ClassVisitor noOpVisitor = new ClassVisitor(Opcodes.ASM9) {}; + + Executable accept = () -> reader.accept(noOpVisitor, ClassReader.EXPAND_FRAMES); + + assertThrows(IllegalArgumentException.class, accept); + } + private static class EmptyClassVisitor extends ClassVisitor { final AnnotationVisitor annotationVisitor = diff --git a/asm/src/test/java/org/objectweb/asm/ClassVisitorTest.java b/asm/src/test/java/org/objectweb/asm/ClassVisitorTest.java index 5baf8a5e..760622b4 100644 --- a/asm/src/test/java/org/objectweb/asm/ClassVisitorTest.java +++ b/asm/src/test/java/org/objectweb/asm/ClassVisitorTest.java @@ -267,10 +267,14 @@ public ModuleVisitor visitModule( return new ModuleVisitor(api, super.visitModule(name, access, version)) { @Override - public void visitMainClass(final @InternalForm String mainClass) {} + public void visitMainClass(final String mainClass) { + // Remove main class. + } @Override - public void visitPackage(final @DotSeparatedIdentifiers String packaze) {} + public void visitPackage(final String packaze) { + // Remove package. + } @Override public void visitRequire( diff --git a/asm/src/test/java/org/objectweb/asm/ClassWriterComputeMaxsTest.java b/asm/src/test/java/org/objectweb/asm/ClassWriterComputeMaxsTest.java index ee642e90..3b8108f4 100644 --- a/asm/src/test/java/org/objectweb/asm/ClassWriterComputeMaxsTest.java +++ b/asm/src/test/java/org/objectweb/asm/ClassWriterComputeMaxsTest.java @@ -1042,8 +1042,7 @@ TestCaseBuilder nop() { } TestCaseBuilder push() { - methodVisitor.visitInsn(Opcodes.ICONST_0); - return this; + return iconst_0(); } TestCaseBuilder push2() { diff --git a/asm/src/test/java/org/objectweb/asm/ClassWriterTest.java b/asm/src/test/java/org/objectweb/asm/ClassWriterTest.java index c720b567..c4133813 100644 --- a/asm/src/test/java/org/objectweb/asm/ClassWriterTest.java +++ b/asm/src/test/java/org/objectweb/asm/ClassWriterTest.java @@ -325,7 +325,7 @@ void testToByteArray_constantPoolSizeTooLarge(final int constantPoolCount) { classWriter.newConst(Integer.valueOf(i)); } - Executable toByteArray = () -> classWriter.toByteArray(); + Executable toByteArray = classWriter::toByteArray; if (constantPoolCount > 65535) { ClassTooLargeException exception = assertThrows(ClassTooLargeException.class, toByteArray); @@ -353,7 +353,7 @@ void testToByteArray_methodCodeSizeTooLarge(final int methodCodeSize) { methodVisitor.visitMaxs(0, 0); methodVisitor.visitEnd(); - Executable toByteArray = () -> classWriter.toByteArray(); + Executable toByteArray = classWriter::toByteArray; if (methodCodeSize > 65535) { MethodTooLargeException exception = assertThrows(MethodTooLargeException.class, toByteArray); @@ -391,7 +391,7 @@ void testToByteArray_computeMaxs_largeSubroutines(final String classFileName) th ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); classReader.accept(classWriter, attributes(), 0); - Executable toByteArray = () -> classWriter.toByteArray(); + Executable toByteArray = classWriter::toByteArray; assertDoesNotThrow(toByteArray); } @@ -651,7 +651,7 @@ void testReadAndWrite_computeMaxs(final PrecompiledClass classParameter, final A @ParameterizedTest @MethodSource(ALL_CLASSES_AND_ALL_APIS) void testReadAndWrite_computeMaxs_newInstance( - final PrecompiledClass classParameter, final Api apiParameter) throws Exception { + final PrecompiledClass classParameter, final Api apiParameter) { byte[] classFile = classParameter.getBytes(); ClassReader classReader = new ClassReader(classFile); ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); diff --git a/asm/src/test/java/org/objectweb/asm/ConstantsTest.java b/asm/src/test/java/org/objectweb/asm/ConstantsTest.java index c746e2e8..1c375ad9 100644 --- a/asm/src/test/java/org/objectweb/asm/ConstantsTest.java +++ b/asm/src/test/java/org/objectweb/asm/ConstantsTest.java @@ -62,7 +62,7 @@ private enum ConstantType { VERIFICATION_TYPE_INFO_TAG, OPCODE, OTHER - }; + } @Test void testAsmVersions() { diff --git a/asm/src/test/java/org/objectweb/asm/MethodVisitorTest.java b/asm/src/test/java/org/objectweb/asm/MethodVisitorTest.java index 0b41ee2a..03767352 100644 --- a/asm/src/test/java/org/objectweb/asm/MethodVisitorTest.java +++ b/asm/src/test/java/org/objectweb/asm/MethodVisitorTest.java @@ -440,7 +440,7 @@ private static class MethodVisitor4Override extends MethodVisitor { this.log = log; } - @Deprecated + @Deprecated(forRemoval = false) @Override public void visitMethodInsn( final int opcode, final @InternalForm String owner, final @Identifier String name, final @MethodDescriptor String descriptor) { diff --git a/asm/src/test/java/org/objectweb/asm/TypeTest.java b/asm/src/test/java/org/objectweb/asm/TypeTest.java index e3b30a89..b69e61e7 100644 --- a/asm/src/test/java/org/objectweb/asm/TypeTest.java +++ b/asm/src/test/java/org/objectweb/asm/TypeTest.java @@ -381,7 +381,7 @@ void testGetDescriptorFromClass() { } @Test - void testGetOpcode() { + void testGetOpcode_ialoadOrStore() { assertEquals(BALOAD, Type.BOOLEAN_TYPE.getOpcode(IALOAD)); assertEquals(BALOAD, Type.BYTE_TYPE.getOpcode(IALOAD)); assertEquals(CALOAD, Type.CHAR_TYPE.getOpcode(IALOAD)); @@ -395,6 +395,10 @@ void testGetOpcode() { assertEquals(AASTORE, Type.getType("Ljava/lang/Object;").getOpcode(IASTORE)); assertEquals(AASTORE, Type.getObjectType("java/lang/Object").getOpcode(IASTORE)); assertEquals(AASTORE, Type.getType("[I").getOpcode(IASTORE)); + } + + @Test + void testGetOpcode_return() { assertEquals(RETURN, Type.VOID_TYPE.getOpcode(Opcodes.IRETURN)); assertEquals(IRETURN, Type.BOOLEAN_TYPE.getOpcode(Opcodes.IRETURN)); assertEquals(IRETURN, Type.BYTE_TYPE.getOpcode(Opcodes.IRETURN)); @@ -409,6 +413,10 @@ void testGetOpcode() { assertEquals(ARETURN, Type.getType("Ljava/lang/Object;").getOpcode(Opcodes.IRETURN)); assertEquals(ARETURN, Type.getObjectType("java/lang/Object").getOpcode(Opcodes.IRETURN)); assertEquals(ARETURN, Type.getType("[I").getOpcode(Opcodes.IRETURN)); + } + + @Test + void testGetOpcode_iadd() { assertEquals(IADD, Type.BOOLEAN_TYPE.getOpcode(IADD)); assertEquals(IADD, Type.BYTE_TYPE.getOpcode(IADD)); assertEquals(IADD, Type.CHAR_TYPE.getOpcode(IADD)); @@ -417,6 +425,10 @@ void testGetOpcode() { assertEquals(FADD, Type.FLOAT_TYPE.getOpcode(IADD)); assertEquals(LADD, Type.LONG_TYPE.getOpcode(IADD)); assertEquals(DADD, Type.DOUBLE_TYPE.getOpcode(IADD)); + } + + @Test + void testGetOpcode_unsupported() { Class expectedException = UnsupportedOperationException.class; assertThrows(expectedException, () -> Type.VOID_TYPE.getOpcode(IADD)); assertThrows(expectedException, () -> Type.VOID_TYPE.getOpcode(ILOAD)); diff --git a/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java b/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java index 66d30e99..3c7c53b1 100644 --- a/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java +++ b/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java @@ -28,7 +28,7 @@ public final class SignaturesProviders { AsmTest.allClassesAndLatestApi() .map(argument -> (PrecompiledClass) argument.get()[0]) .filter(precompiledClass -> !precompiledClass.isMoreRecentThan(AsmTest.Api.ASM7)) - .forEach(precompiledClass -> collectSignatures(precompiledClass)); + .forEach(SignaturesProviders::collectSignatures); assertFalse(CLASS_SIGNATURES.isEmpty()); assertFalse(FIELD_SIGNATURES.isEmpty()); assertFalse(METHOD_SIGNATURES.isEmpty()); diff --git a/benchmarks/src/jmh/java/org/objectweb/asm/benchmarks/AsmAdapter.java b/benchmarks/src/jmh/java/org/objectweb/asm/benchmarks/AsmAdapter.java index d2720b84..3c17336d 100644 --- a/benchmarks/src/jmh/java/org/objectweb/asm/benchmarks/AsmAdapter.java +++ b/benchmarks/src/jmh/java/org/objectweb/asm/benchmarks/AsmAdapter.java @@ -320,7 +320,7 @@ public void visitFieldInsn( } @Override - @Deprecated + @Deprecated(forRemoval = false) public void visitMethodInsn( final int opcode, final @InternalForm String owner, final @Identifier String name, final @MethodDescriptor String descriptor) { ++count; diff --git a/build.gradle b/build.gradle index 80296256..292a3467 100644 --- a/build.gradle +++ b/build.gradle @@ -33,8 +33,7 @@ buildscript { plugins { id 'com.diffplug.spotless' version "6.23.3" apply false } plugins { id 'me.champeau.jmh' version '0.7.2' apply false } -plugins { id 'org.sonarqube' version '4.3.1.3277' apply false } -plugins { id 'org.checkerframework' version '0.6.45' apply false } +plugins { id 'org.sonarqube' version '7.0.0.6105' apply false } description = 'ASM, a very small and fast Java bytecode manipulation framework' @@ -48,7 +47,8 @@ dependencies { allprojects { group = 'org.ow2.asm' - version = '9.9' + (rootProject.hasProperty('release') ? '' : '-SNAPSHOT') + version = '9.10' + (rootProject.hasProperty('release') ? '' : '-SNAPSHOT') + ext.osgi_version_upper_bound = '9.11' } subprojects { @@ -102,8 +102,8 @@ project(':asm-commons') { project(':asm-test') { description = "Utilities for testing ${parent.description}" provides = ['org.objectweb.asm.test'] - depends = ['org.junit.jupiter:junit-jupiter-api:5.10.1', - 'org.junit.jupiter:junit-jupiter-params:5.10.1'] + depends = ['org.junit.jupiter:junit-jupiter-api:5.13.4', + 'org.junit.jupiter:junit-jupiter-params:5.13.4'] } project(':asm-tree') { @@ -234,9 +234,10 @@ subprojects { dependencies { requires.each { projectName -> api project(projectName) } depends.each { artifactName -> api artifactName } - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.1', - 'org.junit.jupiter:junit-jupiter-params:5.10.1' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.1' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.13.4', + 'org.junit.jupiter:junit-jupiter-params:5.13.4' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.13.4' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation project(':asm-test') } @@ -258,6 +259,9 @@ configure(subprojects.findAll{it.provides}) { jacocoTestReport { reports { xml.required = true } classDirectories.setFrom(sourceSets.main.output.classesDirs) + dependsOn ':asm:jar' + dependsOn ':asm-tree:jar' + dependsOn ':asm-commons:jar' } jacocoTestCoverageVerification { classDirectories.setFrom(sourceSets.main.output.classesDirs) @@ -343,7 +347,7 @@ configure(subprojects.findAll{it.provides}) { if (imports) { jar.manifest.attributes( 'Import-Package': - imports.collect{"${it};version=\"${version}\""}.join(','), + imports.collect{"${it};version=\"[${version},${ext.osgi_version_upper_bound})\""}.join(','), 'Module-Requires': transitiveRequires().collect{"${it};transitive=true"}.join(',')) } @@ -354,6 +358,8 @@ configure(subprojects.findAll{it.provides}) { apply plugin: 'org.sonarqube' sonar { properties { property 'sonar.projectKey', "ASM:${project.name}" } + properties { property 'sonar.inclusions', "**/*.java" } + properties { property 'sonar.verbose', "true" } } // Add a task to generate a private javadoc and add it as a dependency of the