jps: CompiledClass accepts multiple source files
[idea/community.git] / jps / jps-builders / src / org / jetbrains / jps / incremental / instrumentation / NotNullInstrumentingBuilder.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.notNullVerification.NotNullVerifyingInstrumenter;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.util.Function;
23 import com.intellij.util.containers.ContainerUtil;
24 import org.jetbrains.annotations.NotNull;
25 import org.jetbrains.annotations.Nullable;
26 import org.jetbrains.jps.ModuleChunk;
27 import org.jetbrains.jps.cmdline.ProjectDescriptor;
28 import org.jetbrains.jps.incremental.BinaryContent;
29 import org.jetbrains.jps.incremental.CompileContext;
30 import org.jetbrains.jps.incremental.CompiledClass;
31 import org.jetbrains.jps.incremental.messages.BuildMessage;
32 import org.jetbrains.jps.incremental.messages.CompilerMessage;
33 import org.jetbrains.jps.model.java.JpsJavaExtensionService;
34 import org.jetbrains.org.objectweb.asm.ClassReader;
35 import org.jetbrains.org.objectweb.asm.ClassWriter;
36 import org.jetbrains.org.objectweb.asm.Opcodes;
37
38 import java.io.File;
39 import java.util.Collection;
40
41 /**
42  * @author Eugene Zhuravlev
43  *         Date: 11/21/12
44  */
45 public class NotNullInstrumentingBuilder extends BaseInstrumentingBuilder{
46   private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.instrumentation.NotNullInstrumentingBuilder");
47
48   public NotNullInstrumentingBuilder() {
49   }
50
51   @NotNull
52   @Override
53   public String getPresentableName() {
54     return "NotNull instrumentation";
55   }
56
57   @Override
58   protected String getProgressMessage() {
59     return "Adding @NotNull assertions...";
60   }
61
62   @Override
63   protected boolean isEnabled(CompileContext context, ModuleChunk chunk) {
64     final ProjectDescriptor pd = context.getProjectDescriptor();
65     return JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(pd.getProject()).isAddNotNullAssertions();
66   }
67
68   @Override
69   protected boolean canInstrument(CompiledClass compiledClass, int classFileVersion) {
70     return classFileVersion >= Opcodes.V1_5;
71   }
72
73   // todo: probably instrument other NotNull-like annotations defined in project settings?
74   @Override
75   @Nullable
76   protected BinaryContent instrument(CompileContext context,
77                                      CompiledClass compiledClass,
78                                      ClassReader reader,
79                                      ClassWriter writer,
80                                      InstrumentationClassFinder finder) {
81     try {
82       if (NotNullVerifyingInstrumenter.processClassFile((FailSafeClassReader)reader, writer)) {
83         return new BinaryContent(writer.toByteArray());
84       }
85     }
86     catch (Throwable e) {
87       LOG.error(e);
88       final Collection<File> sourceFiles = compiledClass.getSourceFiles();
89       String msg = "Cannot instrument " + ContainerUtil.map(sourceFiles, new Function<File, String>() {
90         @Override
91         public String fun(File file) {
92           return file.getName();
93         }
94       }) + ": " + e.getMessage();
95       context.processMessage(new CompilerMessage(getPresentableName(),
96                                                  msg,
97                                                  compiledClass.getSourceFilesPaths(),
98                                                  BuildMessage.Kind.ERROR));
99     }
100     return null;
101   }
102
103 }