mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
eclipse && notnull -> community
This commit is contained in:
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
+184
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user