revert compiler-message to receive only one file
[idea/community.git] / jps / jps-builders / src / org / jetbrains / jps / incremental / instrumentation / BaseInstrumentingBuilder.java
1 /*
2  * Copyright 2000-2012 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.jps.incremental.instrumentation;
17
18 import com.intellij.compiler.instrumentation.FailSafeClassReader;
19 import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
20 import com.intellij.compiler.instrumentation.InstrumenterClassWriter;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.openapi.util.Key;
23 import com.intellij.util.containers.ContainerUtil;
24 import org.jetbrains.annotations.Nullable;
25 import org.jetbrains.jps.ModuleChunk;
26 import org.jetbrains.jps.incremental.*;
27 import org.jetbrains.jps.incremental.messages.BuildMessage;
28 import org.jetbrains.jps.incremental.messages.CompilerMessage;
29 import org.jetbrains.org.objectweb.asm.ClassReader;
30 import org.jetbrains.org.objectweb.asm.ClassWriter;
31
32 /**
33  * @author Eugene Zhuravlev
34  *         Date: 11/25/12
35  */
36 public abstract class BaseInstrumentingBuilder extends ClassProcessingBuilder {
37   private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.instrumentation.BaseInstrumentingBuilder");
38   // every instance of builder must have its own marker!
39   private final Key<Boolean> IS_INSTRUMENTED_KEY = Key.create("_instrumentation_marker_" + getPresentableName());
40
41   public BaseInstrumentingBuilder() {
42     super(BuilderCategory.CLASS_INSTRUMENTER);
43   }
44
45   @Override
46   protected final ExitCode performBuild(CompileContext context, ModuleChunk chunk, InstrumentationClassFinder finder, OutputConsumer outputConsumer) {
47     ExitCode exitCode = ExitCode.NOTHING_DONE;
48     for (CompiledClass compiledClass : outputConsumer.getCompiledClasses().values()) {
49       if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
50         LOG.info("checking " + compiledClass + " by " + getClass());
51       }
52       final BinaryContent originalContent = compiledClass.getContent();
53       final ClassReader reader = new FailSafeClassReader(originalContent.getBuffer(), originalContent.getOffset(), originalContent.getLength());
54       final int version = getClassFileVersion(reader);
55       if (IS_INSTRUMENTED_KEY.get(compiledClass, Boolean.FALSE) || !canInstrument(compiledClass, version)) {
56         // do not instrument the same content twice
57         continue;
58       }
59       final ClassWriter writer = new InstrumenterClassWriter(reader, getAsmClassWriterFlags(version), finder);
60       try {
61         if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
62           LOG.info("instrumenting " + compiledClass + " by " + getClass());
63         }
64         final BinaryContent instrumented = instrument(context, compiledClass, reader, writer, finder);
65         if (instrumented != null) {
66           compiledClass.setContent(instrumented);
67           finder.cleanCachedData(compiledClass.getClassName());
68           IS_INSTRUMENTED_KEY.set(compiledClass, Boolean.TRUE);
69           exitCode = ExitCode.OK;
70         }
71       }
72       catch (Throwable e) {
73         LOG.info(e);
74         final String message = e.getMessage();
75         if (message != null) {
76           context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, message, ContainerUtil.getFirstItem(compiledClass.getSourceFilesPaths())));
77         }
78         else {
79           context.processMessage(new CompilerMessage(getPresentableName(), e));
80         }
81       }
82     }
83     return exitCode;
84   }
85
86   protected abstract boolean canInstrument(CompiledClass compiledClass, int classFileVersion);
87
88   @Nullable
89   protected abstract BinaryContent instrument(CompileContext context,
90                                               CompiledClass compiled,
91                                               ClassReader reader,
92                                               ClassWriter writer,
93                                               InstrumentationClassFinder finder);
94
95 }