diff --git a/java/compiler/javac2/src/com/intellij/ant/ClassFilterAnnotationRegexp.java b/java/compiler/javac2/src/com/intellij/ant/ClassFilterAnnotationRegexp.java new file mode 100644 index 000000000000..bb69d806b570 --- /dev/null +++ b/java/compiler/javac2/src/com/intellij/ant/ClassFilterAnnotationRegexp.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ant; + +import org.apache.tools.ant.types.RegularExpression; + +/** + * A pattern which is used to skip NotNull assertion instrumentation on classes that have at least one annotation matching this pattern. + * + * Example usage: + * + * + * + * + */ +public class ClassFilterAnnotationRegexp extends RegularExpression { +} diff --git a/java/compiler/javac2/src/com/intellij/ant/Javac2.java b/java/compiler/javac2/src/com/intellij/ant/Javac2.java index e5b8aee7130a..d41e5dc70ebd 100644 --- a/java/compiler/javac2/src/com/intellij/ant/Javac2.java +++ b/java/compiler/javac2/src/com/intellij/ant/Javac2.java @@ -25,10 +25,8 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Javac; import org.apache.tools.ant.types.Path; -import org.jetbrains.org.objectweb.asm.ClassReader; -import org.jetbrains.org.objectweb.asm.ClassVisitor; -import org.jetbrains.org.objectweb.asm.ClassWriter; -import org.jetbrains.org.objectweb.asm.Opcodes; +import org.apache.tools.ant.util.regexp.Regexp; +import org.jetbrains.org.objectweb.asm.*; import java.io.*; import java.net.MalformedURLException; @@ -40,6 +38,7 @@ public class Javac2 extends Javac { private ArrayList myFormFiles; private List myNestedFormPathList; private boolean instrumentNotNull = true; + private List myClassFilterAnnotationRegexpList = new ArrayList(0); public Javac2() { } @@ -75,6 +74,16 @@ public class Javac2 extends Javac { this.instrumentNotNull = instrumentNotNull; } + /** + * Allows to specify patterns of annotation class names to skip NotNull instrumentation on classes which have at least one + * annotation matching at least one of the given patterns + * + * @param regexp the regular expression for JVM internal name (slash-separated) of annotations + */ + public void add(final ClassFilterAnnotationRegexp regexp) { + myClassFilterAnnotationRegexpList.add(regexp.getRegexp(getProject())); + } + /** * The overridden setter method that warns about unsupported option. * @@ -425,8 +434,8 @@ public class Javac2 extends Javac { ClassReader reader = new ClassReader(inputStream); int version = getClassFileVersion(reader); - - if (version >= Opcodes.V1_5) { + + if (version >= Opcodes.V1_5 && !shouldBeSkippedByAnnotationPattern(reader)) { ClassWriter writer = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder); if (NotNullVerifyingInstrumenter.processClassFile(reader, writer)) { @@ -471,6 +480,30 @@ public class Javac2 extends Javac { return classfileVersion[0]; } + private boolean shouldBeSkippedByAnnotationPattern(ClassReader reader) { + if (myClassFilterAnnotationRegexpList.isEmpty()) { + return false; + } + + final boolean[] result = new boolean[]{false}; + reader.accept(new ClassVisitor(Opcodes.ASM5) { + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (!result[0]) { + String internalName = Type.getType(desc).getInternalName(); + for (Regexp regexp : myClassFilterAnnotationRegexpList) { + if (regexp.matches(internalName)) { + result[0] = true; + break; + } + } + } + return null; + } + }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + + return result[0]; + } + private void fireError(final String message) { if (failOnError) { throw new BuildException(message, getLocation());