work around javac/asm parameter index mismatch when @NotNull-instrumenting enum constructors

This commit is contained in:
peter
2017-06-23 17:37:47 +02:00
parent 9e4f6491a9
commit 1276b7341b
3 changed files with 38 additions and 13 deletions
@@ -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<Integer, String> paramNames = myMethodParamNames.get(myClassName + '.' + name + desc);
return new FailSafeMethodVisitor(Opcodes.API_VERSION, v) {
private final Map<Integer, NotNullState> myNotNullParams = new LinkedHashMap<Integer, NotNullState>();
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;
}
@@ -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) {
}
}
@@ -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();