use of com.intellij.compiler.instrumentation.FailSafeClassReader in project intellij-community by JetBrains.
the class FormsInstrumenter method instrumentForms.
private Map<File, Collection<File>> instrumentForms(CompileContext context, ModuleChunk chunk, final Map<File, String> chunkSourcePath, final InstrumentationClassFinder finder, Collection<File> forms, OutputConsumer outConsumer) throws ProjectBuildException {
final Map<File, Collection<File>> instrumented = new THashMap<>(FileUtil.FILE_HASHING_STRATEGY);
final Map<String, File> class2form = new HashMap<>();
final MyNestedFormLoader nestedFormsLoader = new MyNestedFormLoader(chunkSourcePath, ProjectPaths.getOutputPathsWithDependents(chunk), finder);
for (File formFile : forms) {
final LwRootContainer rootContainer;
try {
rootContainer = Utils.getRootContainer(formFile.toURI().toURL(), new CompiledClassPropertiesProvider(finder.getLoader()));
} catch (AlienFormFileException e) {
// ignore non-IDEA forms
continue;
} catch (UnexpectedFormElementException e) {
context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, e.getMessage(), formFile.getPath()));
LOG.info(e);
continue;
} catch (UIDesignerException e) {
context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, e.getMessage(), formFile.getPath()));
LOG.info(e);
continue;
} catch (Exception e) {
throw new ProjectBuildException("Cannot process form file " + formFile.getAbsolutePath(), e);
}
final String classToBind = rootContainer.getClassToBind();
if (classToBind == null) {
continue;
}
final CompiledClass compiled = findClassFile(outConsumer, classToBind);
if (compiled == null) {
context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.WARNING, "Class to bind does not exist: " + classToBind, formFile.getAbsolutePath()));
continue;
}
final File alreadyProcessedForm = class2form.get(classToBind);
if (alreadyProcessedForm != null) {
context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.WARNING, formFile.getAbsolutePath() + ": The form is bound to the class " + classToBind + ".\nAnother form " + alreadyProcessedForm.getAbsolutePath() + " is also bound to this class", formFile.getAbsolutePath()));
continue;
}
class2form.put(classToBind, formFile);
for (File file : compiled.getSourceFiles()) {
addBinding(file, formFile, instrumented);
}
try {
context.processMessage(new ProgressMessage("Instrumenting forms... [" + chunk.getPresentableShortName() + "]"));
final BinaryContent originalContent = compiled.getContent();
final ClassReader classReader = new FailSafeClassReader(originalContent.getBuffer(), originalContent.getOffset(), originalContent.getLength());
final int version = ClassProcessingBuilder.getClassFileVersion(classReader);
final InstrumenterClassWriter classWriter = new InstrumenterClassWriter(classReader, ClassProcessingBuilder.getAsmClassWriterFlags(version), finder);
final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, finder, nestedFormsLoader, false, classWriter);
final byte[] patchedBytes = codeGenerator.patchClass(classReader);
if (patchedBytes != null) {
compiled.setContent(new BinaryContent(patchedBytes));
}
final FormErrorInfo[] warnings = codeGenerator.getWarnings();
for (final FormErrorInfo warning : warnings) {
context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.WARNING, warning.getErrorMessage(), formFile.getAbsolutePath()));
}
final FormErrorInfo[] errors = codeGenerator.getErrors();
if (errors.length > 0) {
StringBuilder message = new StringBuilder();
for (final FormErrorInfo error : errors) {
if (message.length() > 0) {
message.append("\n");
}
message.append(formFile.getAbsolutePath()).append(": ").append(error.getErrorMessage());
}
context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, message.toString()));
}
} catch (Exception e) {
context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, "Forms instrumentation failed" + e.getMessage(), formFile.getAbsolutePath()));
}
}
return instrumented;
}
use of com.intellij.compiler.instrumentation.FailSafeClassReader in project intellij-community by JetBrains.
the class Javac2 method instrumentNotNull.
/**
* Instrument classes with NotNull annotations
*
* @param dir the directory with classes to instrument (the directory is processed recursively)
* @param finder the classloader to use
* @return the amount of classes actually affected by instrumentation
*/
private int instrumentNotNull(File dir, final InstrumentationClassFinder finder) {
int instrumented = 0;
final File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
File file = files[i];
final String name = file.getName();
if (name.endsWith(".class")) {
final String path = file.getPath();
log("Adding @NotNull assertions to " + path, Project.MSG_VERBOSE);
try {
final FileInputStream inputStream = new FileInputStream(file);
try {
FailSafeClassReader reader = new FailSafeClassReader(inputStream);
int version = getClassFileVersion(reader);
if (version >= Opcodes.V1_5 && !shouldBeSkippedByAnnotationPattern(reader)) {
ClassWriter writer = new InstrumenterClassWriter(reader, getAsmClassWriterFlags(version), finder);
if (NotNullVerifyingInstrumenter.processClassFile(reader, writer, myNotNullAnnotations.split(";"))) {
final FileOutputStream fileOutputStream = new FileOutputStream(path);
try {
fileOutputStream.write(writer.toByteArray());
instrumented++;
} finally {
fileOutputStream.close();
}
}
}
} finally {
inputStream.close();
}
} catch (IOException e) {
log("Failed to instrument @NotNull assertion for " + path + ": " + e.getMessage(), Project.MSG_WARN);
} catch (Exception e) {
fireError("@NotNull instrumentation failed for " + path + ": " + e.toString());
}
} else if (file.isDirectory()) {
instrumented += instrumentNotNull(file, finder);
}
}
return instrumented;
}
use of com.intellij.compiler.instrumentation.FailSafeClassReader in project intellij-community by JetBrains.
the class OutputFilesSink method save.
public void save(@NotNull final OutputFileObject fileObject) {
final BinaryContent content = fileObject.getContent();
final File srcFile = fileObject.getSourceFile();
boolean isTemp = false;
final JavaFileObject.Kind outKind = fileObject.getKind();
if (srcFile != null && content != null) {
final String sourcePath = FileUtil.toSystemIndependentName(srcFile.getPath());
final JavaSourceRootDescriptor rootDescriptor = myContext.getProjectDescriptor().getBuildRootIndex().findJavaRootDescriptor(myContext, srcFile);
try {
if (rootDescriptor != null) {
isTemp = rootDescriptor.isTemp;
if (!isTemp) {
// first, handle [src->output] mapping and register paths for files_generated event
if (outKind == JavaFileObject.Kind.CLASS) {
// todo: avoid array copying?
myOutputConsumer.registerCompiledClass(rootDescriptor.target, new CompiledClass(fileObject.getFile(), srcFile, fileObject.getClassName(), content));
} else {
myOutputConsumer.registerOutputFile(rootDescriptor.target, fileObject.getFile(), Collections.<String>singleton(sourcePath));
}
}
} else {
// was not able to determine the source root descriptor or the source root is excluded from compilation (e.g. for annotation processors)
if (outKind == JavaFileObject.Kind.CLASS) {
myOutputConsumer.registerCompiledClass(null, new CompiledClass(fileObject.getFile(), srcFile, fileObject.getClassName(), content));
}
}
} catch (IOException e) {
myContext.processMessage(new CompilerMessage(JavaBuilder.BUILDER_NAME, e));
}
if (!isTemp && outKind == JavaFileObject.Kind.CLASS) {
// register in mappings any non-temp class file
try {
final ClassReader reader = new FailSafeClassReader(content.getBuffer(), content.getOffset(), content.getLength());
myMappingsCallback.associate(FileUtil.toSystemIndependentName(fileObject.getFile().getPath()), sourcePath, reader);
} catch (Throwable e) {
// need this to make sure that unexpected errors in, for example, ASM will not ruin the compilation
final String message = "Class dependency information may be incomplete! Error parsing generated class " + fileObject.getFile().getPath();
LOG.info(message, e);
myContext.processMessage(new CompilerMessage(JavaBuilder.BUILDER_NAME, BuildMessage.Kind.WARNING, message + "\n" + CompilerMessage.getTextFromThrowable(e), sourcePath));
}
}
}
if (outKind == JavaFileObject.Kind.CLASS) {
myContext.processMessage(new ProgressMessage("Writing classes... " + myChunkName));
if (!isTemp && srcFile != null) {
mySuccessfullyCompiled.add(srcFile);
}
}
}
use of com.intellij.compiler.instrumentation.FailSafeClassReader in project intellij-community by JetBrains.
the class JpsGroovycRunner method updateDependencies.
void updateDependencies(CompileContext context, List<File> toCompile, MultiMap<T, GroovycOutputParser.OutputItem> successfullyCompiled, final GroovyOutputConsumer outputConsumer, Builder builder) throws IOException {
JavaBuilderUtil.registerFilesToCompile(context, toCompile);
if (!successfullyCompiled.isEmpty()) {
final Callbacks.Backend callback = JavaBuilderUtil.getDependenciesRegistrar(context);
for (Map.Entry<T, Collection<GroovycOutputParser.OutputItem>> entry : successfullyCompiled.entrySet()) {
final T target = entry.getKey();
final Collection<GroovycOutputParser.OutputItem> compiled = entry.getValue();
for (GroovycOutputParser.OutputItem item : compiled) {
final String sourcePath = FileUtil.toSystemIndependentName(item.sourcePath);
final String outputPath = FileUtil.toSystemIndependentName(item.outputPath);
final File outputFile = new File(outputPath);
final File srcFile = new File(sourcePath);
try {
final byte[] bytes = FileUtil.loadFileBytes(outputFile);
if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
LOG.info("registerCompiledClass " + outputFile + " from " + srcFile);
}
outputConsumer.registerCompiledClass(target, srcFile, outputFile, bytes);
callback.associate(outputPath, sourcePath, new FailSafeClassReader(bytes));
} catch (Throwable e) {
// need this to make sure that unexpected errors in, for example, ASM will not ruin the compilation
final String message = "Class dependency information may be incomplete! Error parsing generated class " + item.outputPath;
LOG.info(message, e);
context.processMessage(new CompilerMessage(builder.getPresentableName(), BuildMessage.Kind.WARNING, message + "\n" + CompilerMessage.getTextFromThrowable(e), sourcePath));
}
JavaBuilderUtil.registerSuccessfullyCompiled(context, srcFile);
}
}
}
}
use of com.intellij.compiler.instrumentation.FailSafeClassReader in project intellij-community by JetBrains.
the class NotNullVerifyingInstrumenterTest method prepareTest.
private Class prepareTest(boolean withDebugInfo, String... notNullAnnos) throws IOException {
String base = JavaTestUtil.getJavaTestDataPath() + "/compiler/notNullVerification/";
final String baseClassName = getTestName(false);
String path = base + baseClassName;
String javaPath = path + ".java";
File classesDir = FileUtil.createTempDirectory(baseClassName, "output");
try {
List<String> cmdLine = ContainerUtil.newArrayList("-classpath", base + "annotations.jar", "-d", classesDir.getAbsolutePath());
if (withDebugInfo) {
cmdLine.add("-g");
}
cmdLine.add(javaPath);
com.sun.tools.javac.Main.compile(ArrayUtil.toStringArray(cmdLine));
Class mainClass = null;
final File[] files = classesDir.listFiles();
assertNotNull(files);
Arrays.sort(files, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName()));
boolean modified = false;
MyClassLoader classLoader = new MyClassLoader(getClass().getClassLoader());
for (File file : files) {
final String fileName = file.getName();
byte[] content = FileUtil.loadFileBytes(file);
FailSafeClassReader reader = new FailSafeClassReader(content, 0, content.length);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
modified |= NotNullVerifyingInstrumenter.processClassFile(reader, writer, notNullAnnos);
byte[] instrumented = writer.toByteArray();
final String className = FileUtil.getNameWithoutExtension(fileName);
final Class aClass = classLoader.doDefineClass(className, instrumented);
if (className.equals(baseClassName)) {
mainClass = aClass;
}
}
assertTrue(modified);
assertNotNull("Class " + baseClassName + " not found!", mainClass);
return mainClass;
} finally {
FileUtil.delete(classesDir);
}
}
Aggregations