correctly escape spaces in urls in javac2 ant task: IDEA-88202 javac2 ANT task crashes on @NotNull instrumentation

This commit is contained in:
Eugene Zhuravlev
2012-07-19 14:57:04 +02:00
parent 7ebc3fdd60
commit a03afb0c99
3 changed files with 16 additions and 303 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="false" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_3" inherit-compiler-output="true">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
@@ -1,295 +0,0 @@
/*
* Copyright 2000-2011 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 com.intellij.compiler.instrumentation.InstrumentationClassFinder;
import com.intellij.compiler.instrumentation.InstrumenterClassWriter;
import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter;
import com.intellij.uiDesigner.compiler.*;
import com.intellij.uiDesigner.lw.CompiledClassPropertiesProvider;
import com.intellij.uiDesigner.lw.LwRootContainer;
import org.apache.tools.ant.Project;
import org.jetbrains.asm4.ClassReader;
import org.jetbrains.asm4.ClassVisitor;
import org.jetbrains.asm4.ClassWriter;
import org.jetbrains.asm4.Opcodes;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
/**
* Created by IntelliJ IDEA.
* User: db
* Date: 15.05.11
* Time: 21:36
* To change this template use File | Settings | File Templates.
*/
public class InstrumentationUtil {
public static InstrumentationClassFinder createInstrumentationClassFinder(final String classPath) throws MalformedURLException {
final ArrayList urls = new ArrayList();
for (StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); tokenizer.hasMoreTokens();) {
final String s = tokenizer.nextToken();
urls.add(new File(s).toURL());
}
final URL[] urlsArr = (URL[])urls.toArray(new URL[urls.size()]);
return new InstrumentationClassFinder(urlsArr);
}
public static int getClassFileVersion(ClassReader reader) {
final int[] classfileVersion = new int[1];
reader.accept(new ClassVisitor(Opcodes.ASM4) {
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
classfileVersion[0] = version;
}
}, 0);
return classfileVersion[0];
}
public static int getAsmClassWriterFlags(int version) {
return version >= Opcodes.V1_6 && version != Opcodes.V1_1 ? ClassWriter.COMPUTE_FRAMES : ClassWriter.COMPUTE_MAXS;
}
public static abstract class FormInstrumenter {
protected final List myNestedFormPathList;
protected final File myDestDir;
private final HashMap myClass2form = new HashMap();
private List myFormFiles = null;
public abstract void log(String msg, int option);
public abstract void fireError(String msg);
public abstract List getFormFiles();
public void associate(String formFile, String classFile) {
}
private List formFiles() {
if (myFormFiles == null) {
myFormFiles = getFormFiles();
}
return myFormFiles;
}
protected FormInstrumenter(final File destDir, final List nestedFormPathList) {
myNestedFormPathList = nestedFormPathList;
myDestDir = destDir;
}
private File getClassFile(String className) {
final String classOrInnerName = getClassOrInnerName(className);
if (classOrInnerName == null) return null;
return new File(myDestDir.getAbsolutePath(), classOrInnerName + ".class");
}
private String getClassOrInnerName(String className) {
File classFile = new File(myDestDir.getAbsolutePath(), className + ".class");
if (classFile.exists()) return className;
int position = className.lastIndexOf('/');
if (position == -1) return null;
return getClassOrInnerName(className.substring(0, position) + '$' + className.substring(position + 1));
}
private class AntNestedFormLoader implements NestedFormLoader {
private final InstrumentationClassFinder myClassFinder;
private final List myNestedFormPathList;
private final HashMap myFormCache = new HashMap();
public AntNestedFormLoader(final InstrumentationClassFinder classFinder, List nestedFormPathList) {
myClassFinder = classFinder;
myNestedFormPathList = nestedFormPathList;
}
public LwRootContainer loadForm(String formFilePath) throws Exception {
if (myFormCache.containsKey(formFilePath)) {
return (LwRootContainer)myFormCache.get(formFilePath);
}
String lowerFormFilePath = formFilePath.toLowerCase();
log("Searching for form " + lowerFormFilePath, Project.MSG_VERBOSE);
for (Iterator iterator = formFiles().iterator(); iterator.hasNext();) {
File file = (File)iterator.next();
String name = file.getAbsolutePath().replace(File.separatorChar, '/').toLowerCase();
log("Comparing with " + name, Project.MSG_VERBOSE);
if (name.endsWith(lowerFormFilePath)) {
return loadForm(formFilePath, new FileInputStream(file));
}
}
if (myNestedFormPathList != null) {
for (int i = 0; i < myNestedFormPathList.size(); i++) {
PrefixedPath path = (PrefixedPath)myNestedFormPathList.get(i);
File formFile = path.findFile(formFilePath);
if (formFile != null) {
return loadForm(formFilePath, new FileInputStream(formFile));
}
}
}
InputStream resourceStream = myClassFinder.getResourceAsStream(formFilePath);
if (resourceStream != null) {
return loadForm(formFilePath, resourceStream);
}
throw new Exception("Cannot find nested form file " + formFilePath);
}
private LwRootContainer loadForm(String formFileName, InputStream resourceStream) throws Exception {
final LwRootContainer container = Utils.getRootContainer(resourceStream, null);
myFormCache.put(formFileName, container);
return container;
}
public String getClassToBindName(LwRootContainer container) {
final String className = container.getClassToBind();
String result = getClassOrInnerName(className.replace('.', '/'));
if (result != null) return result.replace('/', '.');
return className;
}
}
public void instrumentForm(final File file, final InstrumentationClassFinder classFinder) {
log("compiling form " + file.getAbsolutePath(), Project.MSG_VERBOSE);
final LwRootContainer rootContainer;
try {
rootContainer = Utils.getRootContainer(file.toURL(), new CompiledClassPropertiesProvider(classFinder.getLoader()));
}
catch (AlienFormFileException e) {
// ignore non-IDEA forms
return;
}
catch (Exception e) {
fireError("Cannot process form file " + file.getAbsolutePath() + ". Reason: " + e);
return;
}
final String classToBind = rootContainer.getClassToBind();
if (classToBind == null) {
return;
}
String name = classToBind.replace('.', '/');
File classFile = getClassFile(name);
if (classFile == null) {
log(file.getAbsolutePath() + ": Class to bind does not exist: " + classToBind, Project.MSG_WARN);
return;
}
final File alreadyProcessedForm = (File)myClass2form.get(classToBind);
if (alreadyProcessedForm != null) {
fireError(file.getAbsolutePath() +
": " +
"The form is bound to the class " +
classToBind +
".\n" +
"Another form " +
alreadyProcessedForm.getAbsolutePath() +
" is also bound to this class.");
return;
}
myClass2form.put(classToBind, file);
associate(file.getAbsolutePath(), name);
try {
int version;
InputStream stream = new FileInputStream(classFile);
try {
version = getClassFileVersion(new ClassReader(stream));
}
finally {
stream.close();
}
AntNestedFormLoader formLoader = new AntNestedFormLoader(classFinder, myNestedFormPathList);
InstrumenterClassWriter classWriter = new InstrumenterClassWriter(InstrumentationUtil.getAsmClassWriterFlags(version), classFinder);
final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, classFinder, formLoader, false, classWriter);
codeGenerator.patchFile(classFile);
final FormErrorInfo[] warnings = codeGenerator.getWarnings();
for (int j = 0; j < warnings.length; j++) {
log(file.getAbsolutePath() + ": " + warnings[j].getErrorMessage(), Project.MSG_WARN);
}
final FormErrorInfo[] errors = codeGenerator.getErrors();
if (errors.length > 0) {
StringBuffer message = new StringBuffer();
for (int j = 0; j < errors.length; j++) {
if (message.length() > 0) {
message.append("\n");
}
message.append(file.getAbsolutePath()).append(": ").append(errors[j].getErrorMessage());
}
fireError(message.toString());
}
}
catch (Exception e) {
fireError("Forms instrumentation failed for " + file.getAbsolutePath() + ": " + e.toString());
}
}
}
public static byte[] instrumentNotNull(final byte[] buffer, final InstrumentationClassFinder loader) {
return instrumentNotNull(new ClassReader (buffer), loader);
}
private static byte[] instrumentNotNull(final ClassReader reader, final InstrumentationClassFinder loader) {
int version = getClassFileVersion(reader);
if (version >= Opcodes.V1_5) {
ClassWriter writer = new InstrumenterClassWriter(getAsmClassWriterFlags(version), loader);
final NotNullVerifyingInstrumenter instrumenter = new NotNullVerifyingInstrumenter(writer);
reader.accept(instrumenter, 0);
if (instrumenter.isModification()) {
return writer.toByteArray();
}
}
return null;
}
public static int instrumentNotNull(final File file, final InstrumentationClassFinder loader) throws IOException {
int instrumented = 0;
final String path = file.getPath();
final FileInputStream inputStream = new FileInputStream(file);
try {
final ClassReader reader = new ClassReader(inputStream);
final byte[] result = instrumentNotNull(reader, loader);
if (result != null) {
final FileOutputStream fileOutputStream = new FileOutputStream(path);
try {
fileOutputStream.write(result);
instrumented++;
}
finally {
fileOutputStream.close();
}
}
}
finally {
inputStream.close();
}
return instrumented;
}
}
@@ -32,10 +32,8 @@ import org.jetbrains.asm4.Opcodes;
import java.io.*;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.net.URL;
import java.util.*;
public class Javac2 extends Javac {
private ArrayList myFormFiles;
@@ -247,7 +245,7 @@ public class Javac2 extends Javac {
log("compiling form " + formFile.getAbsolutePath(), Project.MSG_VERBOSE);
final LwRootContainer rootContainer;
try {
rootContainer = Utils.getRootContainer(formFile.toURL(), new CompiledClassPropertiesProvider(finder.getLoader()));
rootContainer = Utils.getRootContainer(formFile.toURI().toURL(), new CompiledClassPropertiesProvider(finder.getLoader()));
}
catch (AlienFormFileException e) {
// ignore non-IDEA forms
@@ -359,7 +357,7 @@ public class Javac2 extends Javac {
log("classpath=" + classPath, Project.MSG_VERBOSE);
try {
return InstrumentationUtil.createInstrumentationClassFinder(classPath);
return createInstrumentationClassFinder(classPath);
}
catch (MalformedURLException e) {
fireError(e.getMessage());
@@ -488,7 +486,17 @@ public class Javac2 extends Javac {
}
}
private class AntNestedFormLoader implements NestedFormLoader {
private static InstrumentationClassFinder createInstrumentationClassFinder(final String classPath) throws MalformedURLException {
final ArrayList urls = new ArrayList();
for (StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); tokenizer.hasMoreTokens();) {
final String s = tokenizer.nextToken();
urls.add(new File(s).toURI().toURL());
}
final URL[] urlsArr = (URL[])urls.toArray(new URL[urls.size()]);
return new InstrumentationClassFinder(urlsArr);
}
private class AntNestedFormLoader implements NestedFormLoader {
private final ClassLoader myLoader;
private final List myNestedFormPathList;
private final HashMap myFormCache = new HashMap();