eclipse && notnull -> community

This commit is contained in:
Dmitry Jemerov
2009-09-01 19:52:06 +04:00
parent 25c70d2c42
commit 8b695df421
4 changed files with 15 additions and 2 deletions
+1 -1
View File
@@ -15,7 +15,7 @@
<orderEntry type="module" module-name="openapi" />
<orderEntry type="library" name="Trove4j" level="project" />
<orderEntry type="module" module-name="java-runtime" />
<orderEntry type="module" module-name="NotNull" />
<orderEntry type="module" module-name="notNull" />
<orderEntry type="library" name="asm" level="project" />
<orderEntry type="library" name="Eclipse" level="project" />
<orderEntry type="module" module-name="platform-api" />
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="asm" level="project" />
</component>
</module>
@@ -0,0 +1,184 @@
package com.intellij.compiler.notNullVerification;
import org.objectweb.asm.*;
import java.util.ArrayList;
/**
* @author ven
* @noinspection HardCodedStringLiteral
*/
public class NotNullVerifyingInstrumenter extends ClassAdapter {
private boolean myIsModification = false;
private boolean myIsNotStaticInner = false;
private String myClassName;
private String mySuperName;
private static final String ENUM_CLASS_NAME = "java/lang/Enum";
private static final String CONSTRUCTOR_NAME = "<init>";
public NotNullVerifyingInstrumenter(final ClassVisitor classVisitor) {
super(classVisitor);
}
public boolean isModification() {
return myIsModification;
}
public void visit(final int version,
final int access,
final String name,
final String signature,
final String superName,
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 & Opcodes.ACC_STATIC) == 0;
}
}
public MethodVisitor visitMethod(
final int access,
final String name,
final String desc,
final String signature,
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,
signature,
exceptions);
return new MethodAdapter(v) {
private final ArrayList myNotNullParams = new ArrayList();
private boolean myIsNotNull = false;
public Label myThrowLabel;
private Label myStartGeneratedCodeLabel;
public AnnotationVisitor visitParameterAnnotation(
final int parameter,
final String anno,
final boolean visible) {
AnnotationVisitor av;
av = mv.visitParameterAnnotation(parameter,
anno,
visible);
if (isReferenceType(args[parameter]) &&
anno.equals("Lorg/jetbrains/annotations/NotNull;")) {
myNotNullParams.add(new Integer(parameter));
}
return av;
}
public AnnotationVisitor visitAnnotation(String anno,
boolean isRuntime) {
final AnnotationVisitor av = mv.visitAnnotation(anno, isRuntime);
if (isReferenceType(returnType) &&
anno.equals("Lorg/jetbrains/annotations/NotNull;")) {
myIsNotNull = true;
}
return av;
}
public void visitCode() {
if (myNotNullParams.size() > 0) {
myStartGeneratedCodeLabel = new Label();
mv.visitLabel(myStartGeneratedCodeLabel);
}
for (int p = 0; p < myNotNullParams.size(); ++p) {
int var = ((access & Opcodes.ACC_STATIC) == 0) ? 1 : 0;
int param = ((Integer)myNotNullParams.get(p)).intValue();
for (int i = 0; i < param + startParameter; ++i) {
var += args[i].getSize();
}
mv.visitVarInsn(Opcodes.ALOAD, var);
Label end = new Label();
mv.visitJumpInsn(Opcodes.IFNONNULL, end);
generateThrow("java/lang/IllegalArgumentException",
"Argument " + param + " for @NotNull parameter of " + myClassName + "." + name + " must not be null", end);
}
}
public void visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end,
final int index) {
final boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
final boolean isParameter = isStatic ? index < args.length : index <= args.length;
mv.visitLocalVariable(name, desc, signature, (isParameter && myStartGeneratedCodeLabel != null) ? myStartGeneratedCodeLabel : start, end, index);
}
public void visitInsn(int opcode) {
if (opcode == Opcodes.ARETURN && myIsNotNull) {
mv.visitInsn(Opcodes.DUP);
/*generateConditionalThrow("@NotNull method " + myClassName + "." + name + " must not return null",
"java/lang/IllegalStateException");*/
if (myThrowLabel == null) {
Label skipLabel = new Label();
mv.visitJumpInsn(Opcodes.IFNONNULL, skipLabel);
myThrowLabel = new Label();
mv.visitLabel(myThrowLabel);
generateThrow("java/lang/IllegalStateException", "@NotNull method " + myClassName + "." + name + " must not return null",
skipLabel);
}
else {
mv.visitJumpInsn(Opcodes.IFNULL, myThrowLabel);
}
}
mv.visitInsn(opcode);
}
private void generateThrow(final String exceptionClass, final String descr, final Label end) {
String exceptionParamClass = "(Ljava/lang/String;)V";
mv.visitTypeInsn(Opcodes.NEW, exceptionClass);
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn(descr);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL,
exceptionClass,
CONSTRUCTOR_NAME,
exceptionParamClass);
mv.visitInsn(Opcodes.ATHROW);
mv.visitLabel(end);
myIsModification = true;
}
public void visitMaxs(final int maxStack, final int maxLocals) {
try {
super.visitMaxs(maxStack, maxLocals);
}
catch (ArrayIndexOutOfBoundsException e) {
throw new ArrayIndexOutOfBoundsException("maxs processing failed for method " + name + ": " + e.getMessage());
}
}
};
}
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;
}
}
return result;
}
private static boolean isReferenceType(final Type type) {
return type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY;
}
}