diff --git a/java/compiler/instrumentation-util/src/com/intellij/compiler/instrumentation/InstrumentationClassFinder.java b/java/compiler/instrumentation-util/src/com/intellij/compiler/instrumentation/InstrumentationClassFinder.java index bd2c89d8d99f..abde877bb04e 100644 --- a/java/compiler/instrumentation-util/src/com/intellij/compiler/instrumentation/InstrumentationClassFinder.java +++ b/java/compiler/instrumentation-util/src/com/intellij/compiler/instrumentation/InstrumentationClassFinder.java @@ -67,7 +67,7 @@ public class InstrumentationClassFinder { protected Class findClass(String name) throws ClassNotFoundException { final InputStream is = lookupClassBeforeClasspath(name.replace('.', '/')); if (is == null) { - throw new ClassNotFoundException(name); + throw new ClassNotFoundException("Class not found: " + name.replace('/', '.')); // ensure presentable class name in error message } try { final byte[] bytes = loadBytes(is); @@ -104,7 +104,7 @@ public class InstrumentationClassFinder { final InputStream is = getClassBytesAsStream(internalName); if (is == null) { - throw new ClassNotFoundException("Class not found: " + internalName); + throw new ClassNotFoundException("Class not found: " + name.replace('/', '.')); // ensure presentable class name in error message } try { diff --git a/java/compiler/instrumentation-util/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java b/java/compiler/instrumentation-util/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java index 72fbc554a8ca..77bc53816847 100644 --- a/java/compiler/instrumentation-util/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java +++ b/java/compiler/instrumentation-util/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java @@ -39,6 +39,7 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode private String myClassName; private boolean myIsModification = false; + private RuntimeException myPostponedError; public NotNullVerifyingInstrumenter(final ClassVisitor classVisitor) { super(Opcodes.ASM4, classVisitor); @@ -66,12 +67,8 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode private boolean myIsNotNull = false; private Label myStartGeneratedCodeLabel; - public AnnotationVisitor visitParameterAnnotation( - final int parameter, - final String anno, - final boolean visible) { - AnnotationVisitor av; - av = mv.visitParameterAnnotation(parameter, anno, visible); + public AnnotationVisitor visitParameterAnnotation(final int parameter, final String anno, final boolean visible) { + final AnnotationVisitor av = mv.visitParameterAnnotation(parameter, anno, visible); if (isReferenceType(args[parameter]) && anno.equals(NOT_NULL_TYPE)) { myNotNullParams.add(new Integer(parameter)); } @@ -85,8 +82,7 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode @Override public AnnotationVisitor visitAnnotation(String anno, boolean isRuntime) { final AnnotationVisitor av = mv.visitAnnotation(anno, isRuntime); - if (isReferenceType(returnType) && - anno.equals(NOT_NULL_TYPE)) { + if (isReferenceType(returnType) && anno.equals(NOT_NULL_TYPE)) { myIsNotNull = true; } @@ -144,6 +140,7 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode mv.visitLabel(end); myIsModification = true; + processPostponedErrors(); } @Override @@ -151,8 +148,8 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode try { super.visitMaxs(maxStack, maxLocals); } - catch (ArrayIndexOutOfBoundsException e) { - throw new ArrayIndexOutOfBoundsException("Maximums processing failed for " + myClassName + "." + name + ": " + e.getMessage()); + catch (Throwable e) { + registerError(name, "visitMaxs", e); } } }; @@ -161,4 +158,25 @@ public class NotNullVerifyingInstrumenter extends ClassVisitor implements Opcode private static boolean isReferenceType(final Type type) { return type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY; } + + private void registerError(String methodName, String operationName, Throwable e) { + if (myPostponedError == null) { + // throw the first error that occurred + Throwable err = e.getCause(); + if (err == null) { + err = e; + } + myPostponedError = new RuntimeException("Operation '" + operationName + "' failed for " + myClassName + "." + methodName + "(): " + err.getMessage(), err); + } + if (myIsModification) { + processPostponedErrors(); + } + } + + private void processPostponedErrors() { + final RuntimeException error = myPostponedError; + if (error != null) { + throw error; + } + } } diff --git a/plugins/IntelliLang/intellilang-jps-plugin/src/org/jetbrains/jps/intellilang/instrumentation/InstrumentationAdapter.java b/plugins/IntelliLang/intellilang-jps-plugin/src/org/jetbrains/jps/intellilang/instrumentation/InstrumentationAdapter.java index 738b091798d9..4d2a5ac6eedc 100644 --- a/plugins/IntelliLang/intellilang-jps-plugin/src/org/jetbrains/jps/intellilang/instrumentation/InstrumentationAdapter.java +++ b/plugins/IntelliLang/intellilang-jps-plugin/src/org/jetbrains/jps/intellilang/instrumentation/InstrumentationAdapter.java @@ -134,30 +134,35 @@ class InstrumentationAdapter extends MethodVisitor implements Opcodes { } public void visitMaxs(int maxStack, int maxLocals) { - if (myAssertLabel != null) { + try { + if (myAssertLabel != null) { - // next index for synthetic variable that holds return value - final int var = maxLocals + 1; + // next index for synthetic variable that holds return value + final int var = maxLocals + 1; - mv.visitLabel(myAssertLabel); + mv.visitLabel(myAssertLabel); - mv.visitVarInsn(Opcodes.ASTORE, var); + mv.visitVarInsn(Opcodes.ASTORE, var); - final Label end = new Label(); - addPatternTest(myMethodPattern.patternIndex, end, var); + final Label end = new Label(); + addPatternTest(myMethodPattern.patternIndex, end, var); - addPatternAssertion(MessageFormat.format("Return value of method {0}.{1} annotated as @{2} does not match pattern {3}", - myInstrumenter.myClassName, myMethodName, myMethodPattern.annotation, - myMethodPattern.pattern), true); + addPatternAssertion(MessageFormat.format("Return value of method {0}.{1} annotated as @{2} does not match pattern {3}", + myInstrumenter.myClassName, myMethodName, myMethodPattern.annotation, + myMethodPattern.pattern), true); - mv.visitLabel(end); - mv.visitLocalVariable(RETURN_VALUE_NAME, PatternInstrumenter.JAVA_LANG_STRING, null, myAssertLabel, end, var); + mv.visitLabel(end); + mv.visitLocalVariable(RETURN_VALUE_NAME, PatternInstrumenter.JAVA_LANG_STRING, null, myAssertLabel, end, var); - mv.visitVarInsn(Opcodes.ALOAD, var); - mv.visitInsn(Opcodes.ARETURN); + mv.visitVarInsn(Opcodes.ALOAD, var); + mv.visitInsn(Opcodes.ARETURN); + } + + super.visitMaxs(maxStack, maxLocals); + } + catch (Throwable e) { + myInstrumenter.registerError(myMethodName, "visitMaxs", e); } - - super.visitMaxs(maxStack, maxLocals); } @SuppressWarnings({"HardCodedStringLiteral"}) @@ -194,7 +199,7 @@ class InstrumentationAdapter extends MethodVisitor implements Opcodes { addThrow("java/lang/IllegalArgumentException", "(Ljava/lang/String;)V", message); } } - myInstrumenter.myInstrumented = true; + myInstrumenter.markInstrumented(); } private void addThrow(@NonNls String throwableClass, @NonNls String ctorSignature, String message) { diff --git a/plugins/IntelliLang/intellilang-jps-plugin/src/org/jetbrains/jps/intellilang/instrumentation/PatternInstrumenter.java b/plugins/IntelliLang/intellilang-jps-plugin/src/org/jetbrains/jps/intellilang/instrumentation/PatternInstrumenter.java index 6d1bd2d249e3..fe9a4f777b8f 100644 --- a/plugins/IntelliLang/intellilang-jps-plugin/src/org/jetbrains/jps/intellilang/instrumentation/PatternInstrumenter.java +++ b/plugins/IntelliLang/intellilang-jps-plugin/src/org/jetbrains/jps/intellilang/instrumentation/PatternInstrumenter.java @@ -46,7 +46,8 @@ class PatternInstrumenter extends ClassVisitor implements Opcodes { private final Set myProcessedAnnotations = new HashSet(); // checked annotation classes String myClassName; - boolean myInstrumented; + private boolean myInstrumented; + private RuntimeException myPostponedError; boolean myIsNonStaticInnerClass; public PatternInstrumenter(@NotNull String patternAnnotationClassName, ClassVisitor classvisitor, @@ -66,6 +67,11 @@ class PatternInstrumenter extends ClassVisitor implements Opcodes { return myInstrumented; } + void markInstrumented() { + myInstrumented = true; + processPostponedErrors(); + } + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(version, access, name, signature, superName, interfaces); myClassName = name; @@ -273,4 +279,26 @@ class PatternInstrumenter extends ClassVisitor implements Opcodes { // todo } } + + void registerError(String methodName, String operationName, Throwable e) { + if (myPostponedError == null) { + // throw the first error that occurred + Throwable err = e.getCause(); + if (err == null) { + err = e; + } + myPostponedError = new RuntimeException("Operation '" + operationName + "' failed for " + myClassName + "." + methodName + "(): " + err.getMessage(), err); + } + if (myInstrumented) { + processPostponedErrors(); + } + } + + private void processPostponedErrors() { + final RuntimeException error = myPostponedError; + if (error != null) { + throw error; + } + } + }