IDEA-146460 Assertions aren't generated for @NotNull method parameters and return types if @NotNull assertion is changed to TYPE_USE only

This commit is contained in:
peter
2017-06-21 17:19:07 +02:00
parent 7d6928274a
commit f1e4db35a4
4 changed files with 77 additions and 12 deletions
@@ -145,7 +145,7 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode
}
@Override
public MethodVisitor visitMethod(final int access, final String name, String desc, String signature, String[] exceptions) {
public MethodVisitor visitMethod(final int access, final String name, final String desc, String signature, String[] exceptions) {
if ((access & Opcodes.ACC_BRIDGE) != 0) {
return new FailSafeMethodVisitor(Opcodes.API_VERSION, super.visitMethod(access, name, desc, signature, exceptions));
}
@@ -175,16 +175,33 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode
};
}
public AnnotationVisitor visitParameterAnnotation(final int parameter, final String anno, final boolean visible) {
AnnotationVisitor av = mv.visitParameterAnnotation(parameter, anno, visible);
if (isReferenceType(args[parameter]) && myNotNullAnnos.contains(anno)) {
NotNullState state = new NotNullState(anno, IAE_CLASS_NAME);
myNotNullParams.put(new Integer(parameter), state);
av = collectNotNullArgs(av, state);
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
TypeReference ref = new TypeReference(typeRef);
if (ref.getSort() == TypeReference.METHOD_RETURN) {
return checkNotNullMethod(desc, mv.visitTypeAnnotation(typeRef, typePath, desc, visible));
}
else if (anno.equals(SYNTHETIC_TYPE)) {
if (ref.getSort() == TypeReference.METHOD_FORMAL_PARAMETER) {
return checkNotNullParameter(ref.getFormalParameterIndex(), desc, mv.visitTypeAnnotation(typeRef, typePath, desc, visible));
}
return null;
}
public AnnotationVisitor visitParameterAnnotation(final int parameter, final String anno, final boolean visible) {
if (anno.equals(SYNTHETIC_TYPE)) {
// see http://forge.ow2.org/tracker/?aid=307392&group_id=23&atid=100023&func=detail
mySyntheticCount++;
return null;
}
return checkNotNullParameter(parameter, anno, mv.visitParameterAnnotation(parameter, anno, visible));
}
private AnnotationVisitor checkNotNullParameter(int parameter, String anno, AnnotationVisitor av) {
if (isReferenceType(args[parameter]) && myNotNullAnnos.contains(anno)) {
NotNullState state = new NotNullState(anno, IAE_CLASS_NAME);
myNotNullParams.put(parameter, state);
return collectNotNullArgs(av, state);
}
return av;
@@ -192,12 +209,14 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode
@Override
public AnnotationVisitor visitAnnotation(String anno, boolean isRuntime) {
AnnotationVisitor av = mv.visitAnnotation(anno, isRuntime);
return checkNotNullMethod(anno, mv.visitAnnotation(anno, isRuntime));
}
private AnnotationVisitor checkNotNullMethod(String anno, AnnotationVisitor av) {
if (isReferenceType(returnType) && myNotNullAnnos.contains(anno)) {
myMethodNotNull = new NotNullState(anno, ISE_CLASS_NAME);
av = collectNotNullArgs(av, myMethodNotNull);
return collectNotNullArgs(av, myMethodNotNull);
}
return av;
}
@@ -0,0 +1,16 @@
import java.lang.annotation.*;
@Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.PARAMETER})
@interface FooAnno {}
public class TypeUseAndMemberAnnotations {
@FooAnno
public Object foo1() {
return null;
}
public Object foo2(@FooAnno String arg) {
return null;
}
}
@@ -0,0 +1,16 @@
import java.lang.annotation.*;
@Target(ElementType.TYPE_USE)
@interface FooAnno {}
public class TypeUseOnlyAnnotations {
@FooAnno
public Object foo1() {
return null;
}
public Object foo2(@FooAnno String arg) {
return null;
}
}
@@ -182,6 +182,20 @@ public class NotNullVerifyingInstrumenterTest extends UsefulTestCase {
verifyCallThrowsException("@BarAnno method MultipleAnnotations.foo2 must not return null", instance, test.getMethod("foo2"));
}
public void testTypeUseOnlyAnnotations() throws Exception {
Class<?> test = prepareTest(false, "FooAnno");
Object instance = test.newInstance();
verifyCallThrowsException("@FooAnno method TypeUseOnlyAnnotations.foo1 must not return null", instance, test.getMethod("foo1"));
verifyCallThrowsException("Argument 0 for @FooAnno parameter of TypeUseOnlyAnnotations.foo2 must not be null", instance, test.getMethod("foo2", String.class), (String)null);
}
public void testTypeUseAndMemberAnnotations() throws Exception {
Class<?> test = prepareTest(false, "FooAnno");
Object instance = test.newInstance();
verifyCallThrowsException("@FooAnno method TypeUseAndMemberAnnotations.foo1 must not return null", instance, test.getMethod("foo1"));
verifyCallThrowsException("Argument 0 for @FooAnno parameter of TypeUseAndMemberAnnotations.foo2 must not be null", instance, test.getMethod("foo2", String.class), (String)null);
}
public void testMalformedBytecode() throws Exception {
Class<?> testClass = prepareTest(false, AnnotationUtil.NOT_NULL);
verifyCallThrowsException("Argument 0 for @NotNull parameter of MalformedBytecode$NullTest2.handle must not be null", null, testClass.getMethod("main"));
@@ -246,7 +260,7 @@ public class NotNullVerifyingInstrumenterTest extends UsefulTestCase {
mainClass = aClass;
}
}
assertTrue(modified);
assertTrue("Class file not instrumented!", modified);
assertNotNull("Class " + baseClassName + " not found!", mainClass);
return mainClass;
}