[by Alexander Udalov] ability for javac2 to turn off NotNull instrumentation for certain classes

This commit is contained in:
Eugene Zhuravlev
2014-12-26 22:11:36 +01:00
parent 15f3bc7cc6
commit 9b43bba30f
2 changed files with 69 additions and 6 deletions
@@ -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:
*
* <javac2 ...>
* <skip pattern="com/acme/Instrumented"/>
* </javac2>
*/
public class ClassFilterAnnotationRegexp extends RegularExpression {
}
@@ -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<Regexp> myClassFilterAnnotationRegexpList = new ArrayList<Regexp>(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());