From 1276b7341b97de481b0cd52e0455005c4a56752a Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 23 Jun 2017 17:31:25 +0200 Subject: [PATCH] work around javac/asm parameter index mismatch when @NotNull-instrumenting enum constructors --- .../NotNullVerifyingInstrumenter.java | 34 ++++++++++++------- .../TypeUseInEnumConstructor.java | 12 +++++++ .../NotNullVerifyingInstrumenterTest.java | 5 +++ 3 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 java/java-tests/testData/compiler/notNullVerification/TypeUseInEnumConstructor.java diff --git a/java/compiler/instrumentation-util/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java b/java/compiler/instrumentation-util/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java index 6572c5681cc8..83acfe23bb2d 100644 --- a/java/compiler/instrumentation-util/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java +++ b/java/compiler/instrumentation-util/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java @@ -18,6 +18,8 @@ package com.intellij.compiler.notNullVerification; import com.intellij.compiler.instrumentation.FailSafeClassReader; import com.intellij.compiler.instrumentation.FailSafeMethodVisitor; import org.jetbrains.org.objectweb.asm.*; +import org.jetbrains.org.objectweb.asm.signature.SignatureReader; +import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor; import java.io.ByteArrayOutputStream; import java.io.PrintStream; @@ -30,8 +32,6 @@ import java.util.Set; * @author ven */ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcodes { - private static final String SYNTHETIC_CLASS_NAME = "java/lang/Synthetic"; - private static final String SYNTHETIC_TYPE = "L" + SYNTHETIC_CLASS_NAME + ";"; private static final String IAE_CLASS_NAME = "java/lang/IllegalArgumentException"; private static final String ISE_CLASS_NAME = "java/lang/IllegalStateException"; @@ -151,12 +151,15 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode } final Type[] args = Type.getArgumentTypes(desc); + + // see http://forge.ow2.org/tracker/?aid=307392&group_id=23&atid=100023&func=detail + final int syntheticCount = signature == null ? 0 : Math.max(0, args.length - getSignatureParameterCount(signature)); + final Type returnType = Type.getReturnType(desc); final MethodVisitor v = cv.visitMethod(access, name, desc, signature, exceptions); final Map paramNames = myMethodParamNames.get(myClassName + '.' + name + desc); return new FailSafeMethodVisitor(Opcodes.API_VERSION, v) { private final Map myNotNullParams = new LinkedHashMap(); - private int mySyntheticCount = 0; private NotNullState myMethodNotNull; private Label myStartGeneratedCodeLabel; @@ -185,20 +188,13 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode return checkNotNullMethod(desc, av); } if (ref.getSort() == TypeReference.METHOD_FORMAL_PARAMETER) { - return checkNotNullParameter(ref.getFormalParameterIndex(), desc, av); + return checkNotNullParameter(ref.getFormalParameterIndex() + syntheticCount, desc, av); } return av; } public AnnotationVisitor visitParameterAnnotation(final int parameter, final String anno, final boolean visible) { - AnnotationVisitor av = mv.visitParameterAnnotation(parameter, anno, visible); - if (anno.equals(SYNTHETIC_TYPE)) { - // see http://forge.ow2.org/tracker/?aid=307392&group_id=23&atid=100023&func=detail - mySyntheticCount++; - return av; - } - - return checkNotNullParameter(parameter, anno, av); + return checkNotNullParameter(parameter, anno, mv.visitParameterAnnotation(parameter, anno, visible)); } private AnnotationVisitor checkNotNullParameter(int parameter, String anno, AnnotationVisitor av) { @@ -246,7 +242,7 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode String descrPattern = state.getNullParamMessage(paramName); String[] args = state.message != null ? EMPTY_STRING_ARRAY - : new String[]{paramName != null ? paramName : String.valueOf(param - mySyntheticCount), myClassName, name}; + : new String[]{paramName != null ? paramName : String.valueOf(param - syntheticCount), myClassName, name}; reportError(state.exceptionType, end, descrPattern, args); } } @@ -297,6 +293,18 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode }; } + private static int getSignatureParameterCount(String signature) { + final int[] count = {0}; + new SignatureReader(signature).accept(new SignatureVisitor(Opcodes.ASM6) { + @Override + public SignatureVisitor visitParameterType() { + count[0]++; + return super.visitParameterType(); + } + }); + return count[0]; + } + private static boolean isReferenceType(final Type type) { return type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY; } diff --git a/java/java-tests/testData/compiler/notNullVerification/TypeUseInEnumConstructor.java b/java/java-tests/testData/compiler/notNullVerification/TypeUseInEnumConstructor.java new file mode 100644 index 000000000000..3c6576dedd3d --- /dev/null +++ b/java/java-tests/testData/compiler/notNullVerification/TypeUseInEnumConstructor.java @@ -0,0 +1,12 @@ +import java.lang.annotation.*; + +@Target(ElementType.TYPE_USE) +@interface TypeUseNotNull {} + +enum TypeUseInEnumConstructor { + Foo(null, "a", "b"); + + TypeUseInEnumConstructor(String nuS, @TypeUseNotNull String nnS, @TypeUseNotNull String nnS2) { + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/compiler/notNullVerification/NotNullVerifyingInstrumenterTest.java b/java/java-tests/testSrc/com/intellij/java/compiler/notNullVerification/NotNullVerifyingInstrumenterTest.java index bd694d4937e5..f865c36870c3 100644 --- a/java/java-tests/testSrc/com/intellij/java/compiler/notNullVerification/NotNullVerifyingInstrumenterTest.java +++ b/java/java-tests/testSrc/com/intellij/java/compiler/notNullVerification/NotNullVerifyingInstrumenterTest.java @@ -190,6 +190,11 @@ public class NotNullVerifyingInstrumenterTest extends UsefulTestCase { test.getMethod("foo3", List.class).invoke(instance, (List)null); } + public void testTypeUseInEnumConstructor() throws Exception { + Class test = prepareTest(false, "TypeUseNotNull"); + assertSize(1, test.getEnumConstants()); + } + public void testTypeUseAndMemberAnnotations() throws Exception { Class test = prepareTest(false, "FooAnno"); Object instance = test.newInstance();