From 6a8fa26b865037257e879120f80bbe3734b1bd00 Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 5 Aug 2010 13:37:36 +0400 Subject: [PATCH] not-null instrumentation fixed for static inner classes --- .../NotNullVerifyingInstrumenter.java | 24 +------ .../NonStaticInnerClass.java | 12 ++++ .../notNullVerification/StaticInnerClass.java | 12 ++++ .../NotNullVerifyingInstrumenterTest.java | 62 ++++++++++++++----- 4 files changed, 72 insertions(+), 38 deletions(-) create mode 100644 java/java-tests/testData/compiler/notNullVerification/NonStaticInnerClass.java create mode 100644 java/java-tests/testData/compiler/notNullVerification/StaticInnerClass.java diff --git a/java/compiler/notNull/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java b/java/compiler/notNull/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java index 62cf1608aa7d..02abbc67e238 100644 --- a/java/compiler/notNull/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java +++ b/java/compiler/notNull/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java @@ -25,12 +25,9 @@ import java.util.ArrayList; */ public class NotNullVerifyingInstrumenter extends ClassAdapter implements Opcodes { private boolean myIsModification = false; - private boolean myIsNotStaticInner = false; private String myClassName; - private String mySuperName; public static final String NOT_NULL = "org/jetbrains/annotations/NotNull"; public static final String NOT_NULL_ANNO = "L"+ NOT_NULL + ";"; - private static final String ENUM_CLASS_NAME = "java/lang/Enum"; public static final String IAE_CLASS_NAME = "java/lang/IllegalArgumentException"; public static final String ISE_CLASS_NAME = "java/lang/IllegalStateException"; private static final String CONSTRUCTOR_NAME = ""; @@ -51,14 +48,6 @@ public class NotNullVerifyingInstrumenter extends ClassAdapter implements Opcode final String[] interfaces) { super.visit(version, access, name, signature, superName, interfaces); myClassName = name; - mySuperName = superName; - } - - public void visitInnerClass(final String name, final String outerName, final String innerName, final int access) { - super.visitInnerClass(name, outerName, innerName, access); - if (myClassName.equals(name)) { - myIsNotStaticInner = (access & ACC_STATIC) == 0; - } } public MethodVisitor visitMethod( @@ -69,7 +58,6 @@ public class NotNullVerifyingInstrumenter extends ClassAdapter implements Opcode final String[] exceptions) { final Type[] args = Type.getArgumentTypes(desc); final Type returnType = Type.getReturnType(desc); - final int startParameter = getStartParameterIndex(name); MethodVisitor v = cv.visitMethod(access, name, desc, @@ -123,7 +111,7 @@ public class NotNullVerifyingInstrumenter extends ClassAdapter implements Opcode for (int p = 0; p < myNotNullParams.size(); ++p) { int var = ((access & ACC_STATIC) == 0) ? 1 : 0; int param = ((Integer)myNotNullParams.get(p)).intValue(); - for (int i = 0; i < startParameter + param; ++i) { + for (int i = 0; i < param; ++i) { var += args[i].getSize(); } mv.visitVarInsn(ALOAD, var); @@ -192,16 +180,6 @@ public class NotNullVerifyingInstrumenter extends ClassAdapter implements Opcode }; } - private int getStartParameterIndex(final String name) { - int result = 0; - if (CONSTRUCTOR_NAME.equals(name)) { - if (myIsNotStaticInner) { - result += 1; - } - } - return result; - } - 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/NonStaticInnerClass.java b/java/java-tests/testData/compiler/notNullVerification/NonStaticInnerClass.java new file mode 100644 index 000000000000..c3613fad6df9 --- /dev/null +++ b/java/java-tests/testData/compiler/notNullVerification/NonStaticInnerClass.java @@ -0,0 +1,12 @@ +import org.jetbrains.annotations.NotNull; + +public class NonStaticInnerClass { + public NonStaticInnerClass() { + new Inner(""); + } + + public class Inner { + public Inner(@NotNull String s) { + } + } +} diff --git a/java/java-tests/testData/compiler/notNullVerification/StaticInnerClass.java b/java/java-tests/testData/compiler/notNullVerification/StaticInnerClass.java new file mode 100644 index 000000000000..a08109042af9 --- /dev/null +++ b/java/java-tests/testData/compiler/notNullVerification/StaticInnerClass.java @@ -0,0 +1,12 @@ +import org.jetbrains.annotations.NotNull; + +public class StaticInnerClass { + public StaticInnerClass() { + new Inner(""); + } + + public static class Inner { + public Inner(@NotNull String s) { + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenterTest.java b/java/java-tests/testSrc/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenterTest.java index e8d6dd9d56cf..b512920c983e 100644 --- a/java/java-tests/testSrc/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenterTest.java +++ b/java/java-tests/testSrc/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenterTest.java @@ -69,6 +69,16 @@ public class NotNullVerifyingInstrumenterTest extends UsefulTestCase { assertNotNull(field); } + public void testStaticInnerClass() throws Exception { + final Class aClass = prepareTest(); + assertNotNull(aClass.newInstance()); + } + + public void testNonStaticInnerClass() throws Exception { + final Class aClass = prepareTest(); + assertNotNull(aClass.newInstance()); + } + private static void verifyCallThrowsException(final String expectedError, final Object instance, final Method method, final Object... args) throws IllegalAccessException { String exceptionText = null; try { @@ -85,27 +95,48 @@ public class NotNullVerifyingInstrumenterTest extends UsefulTestCase { private Class prepareTest() throws IOException { String base = JavaTestUtil.getJavaTestDataPath() + "/compiler/notNullVerification/"; - String path = base + getTestName(false); + final String baseClassName = getTestName(false); + String path = base + baseClassName; String javaPath = path + ".java"; - String classPath = path + ".class"; + File classesDir = FileUtil.createTempDirectory(baseClassName, "output"); + 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()); + com.sun.tools.javac.Main.compile(new String[] { "-classpath", base+"annotations.jar", "-d", classesDir.getAbsolutePath(), javaPath } ); + Class mainClass = null; + final File[] files = classesDir.listFiles(); + boolean modified = false; MyClassLoader classLoader = new MyClassLoader(getClass().getClassLoader()); - byte[] instrumented = writer.toByteArray(); - return classLoader.doDefineClass(getTestName(false), instrumented); + for (File file : files) { + final String fileName = file.getName(); + FileInputStream stream = new FileInputStream(file); + byte[] content; + try { + content = FileUtil.adaptiveLoadBytes(stream); + } + finally { + 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); + modified |= instrumenter.isModification(); + + byte[] instrumented = writer.toByteArray(); + final String className = FileUtil.getNameWithoutExtension(fileName); + final Class aClass = classLoader.doDefineClass(className, instrumented); + if (className.equals(baseClassName)) { + mainClass = aClass; + } + } + assertTrue(modified); + assertNotNull("Class " + baseClassName + " not found!", mainClass); + return mainClass; } finally { - FileUtil.delete(new File(classPath)); + FileUtil.delete(classesDir); } } @@ -114,6 +145,7 @@ public class NotNullVerifyingInstrumenterTest extends UsefulTestCase { super(parent); } + public Class doDefineClass(String name, byte[] data) { return defineClass(name, data, 0, data.length); }