fix @NotNull instrumentation for enum constructor parameters with ASM 3.3 (IDEA-56943); move NotNullVerifyingInstrumenterTest to java-tests

This commit is contained in:
Dmitry Jemerov
2010-07-30 21:33:38 +04:00
parent a847515b92
commit 0ac2793995
7 changed files with 156 additions and 12 deletions
@@ -93,15 +93,13 @@ public class NotNullVerifyingInstrumenter extends ClassAdapter implements Opcode
av = mv.visitParameterAnnotation(parameter,
anno,
visible);
if (isReferenceType(args[parameter])) {
if (anno.equals(NOT_NULL_ANNO)) {
myNotNullParams.add(new Integer(parameter));
}
else if (anno.equals("Ljava/lang/Synthetic;")) {
// See asm r1278 for what we do this,
// http://forge.objectweb.org/tracker/index.php?func=detail&aid=307392&group_id=23&atid=100023
mySyntheticCount++;
}
if (isReferenceType(args[parameter]) && anno.equals(NOT_NULL_ANNO)) {
myNotNullParams.add(new Integer(parameter));
}
else if (anno.equals("Ljava/lang/Synthetic;")) {
// See asm r1278 for what we do this,
// http://forge.objectweb.org/tracker/index.php?func=detail&aid=307392&group_id=23&atid=100023
mySyntheticCount++;
}
return av;
}
@@ -197,9 +195,6 @@ public class NotNullVerifyingInstrumenter extends ClassAdapter implements Opcode
private int getStartParameterIndex(final String name) {
int result = 0;
if (CONSTRUCTOR_NAME.equals(name)) {
if (mySuperName.equals(ENUM_CLASS_NAME)) {
result += 2;
}
if (myIsNotStaticInner) {
result += 1;
}
+3
View File
@@ -15,6 +15,9 @@
<orderEntry type="module" module-name="platform-api" />
<orderEntry type="library" name="Velocity" level="project" />
<orderEntry type="module" module-name="java-i18n" />
<orderEntry type="module" module-name="compiler-impl" />
<orderEntry type="library" name="asm" level="project" />
<orderEntry type="module" module-name="notNull" />
</component>
</module>
@@ -0,0 +1,11 @@
import org.jetbrains.annotations.NotNull;
public enum EnumConstructor {
Value("label");
private final String label;
EnumConstructor(@NotNull String label) {
this.label = label;
}
}
@@ -0,0 +1,9 @@
import org.jetbrains.annotations.NotNull;
public class MultipleReturns {
@NotNull public Object test(int i) {
if (i == 0) return null;
if (i == 1) return null;
return null;
}
}
@@ -0,0 +1,7 @@
import org.jetbrains.annotations.NotNull;
public class SimpleReturn {
@NotNull public Object test() {
return null;
}
}
@@ -0,0 +1,119 @@
package com.intellij.compiler.notNullVerification;
import com.intellij.JavaTestUtil;
import com.intellij.compiler.PsiClassWriter;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.testFramework.IdeaTestCase;
import com.intellij.testFramework.UsefulTestCase;
import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
import com.intellij.testFramework.fixtures.JavaTestFixtureFactory;
import com.intellij.testFramework.fixtures.TestFixtureBuilder;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author yole
*/
public class NotNullVerifyingInstrumenterTest extends UsefulTestCase {
private IdeaProjectTestFixture myFixture;
@SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"})
public NotNullVerifyingInstrumenterTest() {
IdeaTestCase.initPlatformPrefix();
}
@Override
protected void setUp() throws Exception {
super.setUp();
final JavaTestFixtureFactory fixtureFactory = JavaTestFixtureFactory.getFixtureFactory();
final TestFixtureBuilder<IdeaProjectTestFixture> testFixtureBuilder = fixtureFactory.createLightFixtureBuilder();
myFixture = testFixtureBuilder.getFixture();
myFixture.setUp();
}
@Override
protected void tearDown() throws Exception {
myFixture.tearDown();
super.tearDown();
}
public void testSimpleReturn() throws Exception {
Class testClass = prepareTest();
Object instance = testClass.newInstance();
Method method = testClass.getMethod("test");
verifyCallThrowsException("@NotNull method SimpleReturn.test must not return null", instance, method);
}
public void testMultipleReturns() throws Exception {
Class testClass = prepareTest();
Object instance = testClass.newInstance();
Method method = testClass.getMethod("test", int.class);
verifyCallThrowsException("@NotNull method MultipleReturns.test must not return null", instance, method, 1);
}
public void testEnumConstructor() throws Exception {
Class testClass = prepareTest();
Object field = testClass.getField("Value");
assertNotNull(field);
}
private static void verifyCallThrowsException(final String expectedError, final Object instance, final Method method, final Object... args) throws IllegalAccessException {
String exceptionText = null;
try {
method.invoke(instance, args);
}
catch(InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof IllegalStateException) {
exceptionText = cause.getMessage();
}
}
assertEquals(expectedError, exceptionText);
}
private Class prepareTest() throws IOException {
String base = JavaTestUtil.getJavaTestDataPath() + "/compiler/notNullVerification/";
String path = base + getTestName(false);
String javaPath = path + ".java";
String classPath = path + ".class";
try {
com.sun.tools.javac.Main.compile(new String[] { "-classpath", base+"annotations.jar", javaPath } );
FileInputStream stream = new FileInputStream(classPath);
byte[] content = FileUtil.adaptiveLoadBytes(stream);
stream.close();
ClassReader reader = new ClassReader(content, 0, content.length);
ClassWriter writer = new PsiClassWriter(myFixture.getProject(), false);
final NotNullVerifyingInstrumenter instrumenter = new NotNullVerifyingInstrumenter(writer);
reader.accept(instrumenter, 0);
assertTrue(instrumenter.isModification());
MyClassLoader classLoader = new MyClassLoader(getClass().getClassLoader());
byte[] instrumented = writer.toByteArray();
return classLoader.doDefineClass(getTestName(false), instrumented);
}
finally {
FileUtil.delete(new File(classPath));
}
}
private static class MyClassLoader extends ClassLoader {
public MyClassLoader(ClassLoader parent) {
super(parent);
}
public Class doDefineClass(String name, byte[] data) {
return defineClass(name, data, 0, data.length);
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
return super.loadClass(name);
}
}
}