Merge branch 'master' into upsource-master

This commit is contained in:
Evgeny Pasynkov
2012-05-30 15:03:07 +02:00
29 changed files with 1451 additions and 772 deletions
@@ -52,7 +52,6 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import org.apache.oro.text.regex.*;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -74,6 +73,12 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.CompilerConfiguration");
@NonNls public static final String TESTS_EXTERNAL_COMPILER_HOME_PROPERTY_NAME = "tests.external.compiler.home";
public static final int DEPENDENCY_FORMAT_VERSION = 55;
private static final Comparator<String> ALPHA_COMPARATOR = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
};
@SuppressWarnings({"WeakerAccess"}) public String DEFAULT_COMPILER;
@NotNull private BackendCompiler myDefaultJavaCompiler;
@@ -96,15 +101,14 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
{
loadDefaultWildcardPatterns();
}
private boolean myEnableAnnotationProcessors = false;
private final Map<String, String> myProcessorsMap = new HashMap<String, String>(); // map: AnnotationProcessorName -> options
private boolean myObtainProcessorsFromClasspath = true;
private String myProcessorPath = "";
private final Map<Module, String> myProcessedModules = new HashMap<Module, String>();
private final Map<String, String> myModuleNames = new HashMap<String, String>();
private boolean myAddNotNullAssertions = true;
private final ProcessorConfigProfile myDefaultProcessorsProfile = new ProcessorConfigProfile("Default");
private final List<ProcessorConfigProfile> myModuleProcessorProfiles = new ArrayList<ProcessorConfigProfile>();
// the map is calculated by module processor profiles list for faster access to module settings
private Map<Module, ProcessorConfigProfile> myProcessorsProfilesMap = null;
@Nullable
private String myBytecodeTargetLevel = null; // null means compiler default
private final Map<String, String> myModuleBytecodeTarget = new java.util.HashMap<String, String>();
@@ -116,16 +120,11 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
Disposer.register(project, myExcludedEntriesConfiguration);
project.getMessageBus().connect(project).subscribe(ProjectTopics.MODULES, new ModuleAdapter() {
public void beforeModuleRemoved(Project project, Module module) {
myProcessedModules.remove(module);
myModuleNames.remove(module.getName());
getAnnotationProcessingConfiguration(module).removeModuleName(module.getName());
}
public void moduleAdded(Project project, Module module) {
final String moduleName = module.getName();
if (myModuleNames.containsKey(moduleName)) {
final String dirName = myModuleNames.remove(moduleName);
myProcessedModules.put(module, dirName);
}
myProcessorsProfilesMap = null; // clear cache
}
});
}
@@ -376,55 +375,62 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
myAddNotNullAssertions = enabled;
}
@NotNull
public ProcessorConfigProfile getDefaultProcessorProfile() {
return myDefaultProcessorsProfile;
}
public void setDefaultProcessorProfile(ProcessorConfigProfile profile) {
myDefaultProcessorsProfile.initFrom(profile);
}
@NotNull
public List<ProcessorConfigProfile> getModuleProcessorProfiles() {
return myModuleProcessorProfiles;
}
public void setModuleProcessorProfiles(Collection<ProcessorConfigProfile> moduleProfiles) {
myModuleProcessorProfiles.clear();
myModuleProcessorProfiles.addAll(moduleProfiles);
}
@Override
@NotNull
public ProcessorConfigProfile getAnnotationProcessingConfiguration(Module module) {
Map<Module, ProcessorConfigProfile> map = myProcessorsProfilesMap;
if (map == null) {
map = new HashMap<Module, ProcessorConfigProfile>();
final Map<String, Module> namesMap = new HashMap<String, Module>();
for (Module m : ModuleManager.getInstance(module.getProject()).getModules()) {
namesMap.put(m.getName(), m);
}
if (!namesMap.isEmpty()) {
for (ProcessorConfigProfile profile : myModuleProcessorProfiles) {
for (String name : profile.getModuleNames()) {
final Module mod = namesMap.get(name);
if (mod != null) {
map.put(mod, profile);
}
}
}
}
myProcessorsProfilesMap = map;
}
final ProcessorConfigProfile profile = map.get(module);
return profile != null? profile : myDefaultProcessorsProfile;
}
@Override
public boolean isAnnotationProcessorsEnabled() {
return myEnableAnnotationProcessors;
}
public void setAnnotationProcessorsEnabled(boolean enableAnnotationProcessors) {
myEnableAnnotationProcessors = enableAnnotationProcessors;
}
public boolean isObtainProcessorsFromClasspath() {
return myObtainProcessorsFromClasspath;
}
public void setObtainProcessorsFromClasspath(boolean obtainProcessorsFromClasspath) {
myObtainProcessorsFromClasspath = obtainProcessorsFromClasspath;
}
public String getProcessorPath() {
return myProcessorPath;
}
public void setProcessorsPath(String processorsPath) {
myProcessorPath = processorsPath;
}
public Map<String, String> getAnnotationProcessorsMap() {
return Collections.unmodifiableMap(myProcessorsMap);
}
public void setAnnotationProcessorsMap(Map<String, String> map) {
myProcessorsMap.clear();
myProcessorsMap.putAll(map);
}
public void setAnotationProcessedModules(Map<Module, String> modules) {
myProcessedModules.clear();
myModuleNames.clear();
myProcessedModules.putAll(modules);
}
public Map<Module, String> getAnotationProcessedModules() {
return Collections.unmodifiableMap(myProcessedModules);
}
public boolean isAnnotationProcessingEnabled(Module module) {
return myProcessedModules.containsKey(module);
}
public String getGeneratedSourceDirName(Module module) {
return myProcessedModules.get(module);
if (myDefaultProcessorsProfile.isEnabled()) {
return true;
}
for (ProcessorConfigProfile profile : myModuleProcessorProfiles) {
if (profile.isEnabled()) {
return true;
}
}
return false;
}
private void addWildcardResourcePattern(@NonNls final String wildcardPattern) throws MalformedPatternException {
@@ -579,21 +585,26 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
}
// property names
@NonNls private static final String EXCLUDE_FROM_COMPILE = "excludeFromCompile";
@NonNls private static final String RESOURCE_EXTENSIONS = "resourceExtensions";
@NonNls private static final String ANNOTATION_PROCESSING = "annotationProcessing";
@NonNls private static final String BYTECODE_TARGET_LEVEL = "bytecodeTargetLevel";
@NonNls private static final String WILDCARD_RESOURCE_PATTERNS = "wildcardResourcePatterns";
@NonNls private static final String ENTRY = "entry";
@NonNls private static final String NAME = "name";
@NonNls private static final String ADD_NOTNULL_ASSERTIONS = "addNotNullAssertions";
private static final String EXCLUDE_FROM_COMPILE = "excludeFromCompile";
private static final String RESOURCE_EXTENSIONS = "resourceExtensions";
private static final String ANNOTATION_PROCESSING = "annotationProcessing";
private static final String BYTECODE_TARGET_LEVEL = "bytecodeTargetLevel";
private static final String WILDCARD_RESOURCE_PATTERNS = "wildcardResourcePatterns";
private static final String ADD_NOTNULL_ASSERTIONS = "addNotNullAssertions";
private static final String ENTRY = "entry";
private static final String NAME = "name";
private static final String VALUE = "value";
private static final String ENABLED = "enabled";
private static final String OPTION = "option";
private static final String MODULE = "module";
public void readExternal(Element parentNode) throws InvalidDataException {
DefaultJDOMExternalizer.readExternal(this, parentNode);
final Element notNullAssertions = parentNode.getChild(ADD_NOTNULL_ASSERTIONS);
if (notNullAssertions != null) {
myAddNotNullAssertions = Boolean.valueOf(notNullAssertions.getAttributeValue("enabled", "true"));
myAddNotNullAssertions = Boolean.valueOf(notNullAssertions.getAttributeValue(ENABLED, "true"));
}
Element node = parentNode.getChild(EXCLUDE_FROM_COMPILE);
@@ -608,7 +619,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
for (final Object o : node.getChildren(ENTRY)) {
Element element = (Element)o;
String pattern = element.getAttributeValue(NAME);
if (pattern != null && !"".equals(pattern)) {
if (!StringUtil.isEmpty(pattern)) {
addRegexpPattern(pattern);
}
}
@@ -621,7 +632,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
for (final Object o : node.getChildren(ENTRY)) {
final Element element = (Element)o;
String pattern = element.getAttributeValue(NAME);
if (pattern != null && !"".equals(pattern)) {
if (!StringUtil.isEmpty(pattern)) {
addWildcardResourcePattern(pattern);
}
}
@@ -631,69 +642,41 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
throw new InvalidDataException(e);
}
myModuleProcessorProfiles.clear();
myProcessorsProfilesMap = null;
final Element annotationProcessingSettings = parentNode.getChild(ANNOTATION_PROCESSING);
if (annotationProcessingSettings != null) {
myEnableAnnotationProcessors = Boolean.valueOf(annotationProcessingSettings.getAttributeValue("enabled", "false"));
myObtainProcessorsFromClasspath = Boolean.valueOf(annotationProcessingSettings.getAttributeValue("useClasspath", "true"));
final StringBuilder pathBuilder = new StringBuilder();
for (Element pathElement : (Collection<Element>)annotationProcessingSettings.getChildren("processorPath")) {
final String path = pathElement.getAttributeValue("value");
if (path != null) {
if (pathBuilder.length() > 0) {
pathBuilder.append(File.pathSeparator);
}
pathBuilder.append(path);
for (Object elem : annotationProcessingSettings.getChildren("profile")) {
final Element profileElement = (Element)elem;
final boolean isDefault = "true".equals(profileElement.getAttributeValue("default"));
if (isDefault) {
readProfile(profileElement, myDefaultProcessorsProfile);
}
else {
final ProcessorConfigProfile profile = new ProcessorConfigProfile("");
readProfile(profileElement, profile);
myModuleProcessorProfiles.add(profile);
}
}
myProcessorPath = pathBuilder.toString();
}
myProcessorsMap.clear();
for (Element processorChild : (Collection<Element>)annotationProcessingSettings.getChildren("processor")) {
final String name = processorChild.getAttributeValue("name");
final String options = processorChild.getAttributeValue("options", "");
myProcessorsMap.put(name, options);
}
myProcessedModules.clear();
myModuleNames.clear();
final Collection<Element> processed = (Collection<Element>)annotationProcessingSettings.getChildren("processModule");
if (!processed.isEmpty()) {
final Map<String, Module> moduleMap = new HashMap<String, Module>();
for (Module module : myModuleManager.getModules()) {
moduleMap.put(module.getName(), module);
myBytecodeTargetLevel = null;
myModuleBytecodeTarget.clear();
final Element bytecodeTargetElement = parentNode.getChild(BYTECODE_TARGET_LEVEL);
if (bytecodeTargetElement != null) {
myBytecodeTargetLevel = bytecodeTargetElement.getAttributeValue("target");
for (Element elem : (Collection<Element>)bytecodeTargetElement.getChildren(MODULE)) {
final String name = elem.getAttributeValue(NAME);
if (name == null) {
continue;
}
for (Element moduleElement : processed) {
final String name = moduleElement.getAttributeValue("name");
final String dirname = moduleElement.getAttributeValue("generatedDirName");
if (name != null) {
final Module module = moduleMap.get(name);
if (module != null) {
myProcessedModules.put(module, dirname);
}
else {
myModuleNames.put(name, dirname);
}
}
}
}
myBytecodeTargetLevel = null;
myModuleBytecodeTarget.clear();
final Element bytecodeTargetElement = parentNode.getChild(BYTECODE_TARGET_LEVEL);
if (bytecodeTargetElement != null) {
myBytecodeTargetLevel = bytecodeTargetElement.getAttributeValue("target");
for (Element elem : (Collection<Element>)bytecodeTargetElement.getChildren("module")) {
final String name = elem.getAttributeValue("name");
if (name == null) {
continue;
}
final String target = elem.getAttributeValue("target");
if (target == null) {
continue;
}
myModuleBytecodeTarget.put(name, target);
final String target = elem.getAttributeValue("target");
if (target == null) {
continue;
}
myModuleBytecodeTarget.put(name, target);
}
}
}
@@ -702,88 +685,42 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
DefaultJDOMExternalizer.writeExternal(this, parentNode);
if (myAddNotNullAssertions != true) {
final Element notNullAssertions = new Element(ADD_NOTNULL_ASSERTIONS);
notNullAssertions.setAttribute("enabled", String.valueOf(myAddNotNullAssertions));
parentNode.addContent(notNullAssertions);
addChild(parentNode, ADD_NOTNULL_ASSERTIONS).setAttribute(ENABLED, String.valueOf(myAddNotNullAssertions));
}
if(myExcludedEntriesConfiguration.getExcludeEntryDescriptions().length > 0) {
Element newChild = new Element(EXCLUDE_FROM_COMPILE);
myExcludedEntriesConfiguration.writeExternal(newChild);
parentNode.addContent(newChild);
myExcludedEntriesConfiguration.writeExternal(addChild(parentNode, EXCLUDE_FROM_COMPILE));
}
final Element newChild = new Element(RESOURCE_EXTENSIONS);
final Element newChild = addChild(parentNode, RESOURCE_EXTENSIONS);
for (final String pattern : getRegexpPatterns()) {
final Element entry = new Element(ENTRY);
entry.setAttribute(NAME, pattern);
newChild.addContent(entry);
addChild(newChild, ENTRY).setAttribute(NAME, pattern);
}
parentNode.addContent(newChild);
if (myWildcardPatternsInitialized || !myWildcardPatterns.isEmpty()) {
final Element wildcardPatterns = new Element(WILDCARD_RESOURCE_PATTERNS);
final Element wildcardPatterns = addChild(parentNode, WILDCARD_RESOURCE_PATTERNS);
for (final String wildcardPattern : myWildcardPatterns) {
final Element entry = new Element(ENTRY);
entry.setAttribute(NAME, wildcardPattern);
wildcardPatterns.addContent(entry);
addChild(wildcardPatterns, ENTRY).setAttribute(NAME, wildcardPattern);
}
parentNode.addContent(wildcardPatterns);
}
final Element annotationProcessingSettings = new Element(ANNOTATION_PROCESSING);
parentNode.addContent(annotationProcessingSettings);
annotationProcessingSettings.setAttribute("enabled", String.valueOf(myEnableAnnotationProcessors));
annotationProcessingSettings.setAttribute("useClasspath", String.valueOf(myObtainProcessorsFromClasspath));
if (myProcessorPath.length() > 0) {
final StringTokenizer tokenizer = new StringTokenizer(myProcessorPath, File.pathSeparator, false);
while (tokenizer.hasMoreTokens()) {
final String path = tokenizer.nextToken();
final Element pathElement = new Element("processorPath");
annotationProcessingSettings.addContent(pathElement);
pathElement.setAttribute("value", path);
}
}
for (Map.Entry<String, String> entry : myProcessorsMap.entrySet()) {
final Element processor = new Element("processor");
annotationProcessingSettings.addContent(processor);
processor.setAttribute("name", entry.getKey());
processor.setAttribute("options", entry.getValue());
}
final List<Module> modules = new ArrayList<Module>(myProcessedModules.keySet());
Collections.sort(modules, new Comparator<Module>() {
public int compare(Module o1, Module o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
});
for (Module module : modules) {
final Element moduleElement = new Element("processModule");
annotationProcessingSettings.addContent(moduleElement);
moduleElement.setAttribute("name", module.getName());
final String dirName = myProcessedModules.get(module);
if (dirName != null && dirName.length() > 0) {
moduleElement.setAttribute("generatedDirName", dirName);
}
final Element annotationProcessingSettings = addChild(parentNode, ANNOTATION_PROCESSING);
writeProfile(addChild(annotationProcessingSettings, "profile").setAttribute("default", "true"), myDefaultProcessorsProfile);
for (ProcessorConfigProfile profile : myModuleProcessorProfiles) {
writeProfile(addChild(annotationProcessingSettings, "profile").setAttribute("default", "false"), profile);
}
if (!StringUtil.isEmpty(myBytecodeTargetLevel) || !myModuleBytecodeTarget.isEmpty()) {
final Element bytecodeTarget = new Element(BYTECODE_TARGET_LEVEL);
parentNode.addContent(bytecodeTarget);
final Element bytecodeTarget = addChild(parentNode, BYTECODE_TARGET_LEVEL);
if (!StringUtil.isEmpty(myBytecodeTargetLevel)) {
bytecodeTarget.setAttribute("target", myBytecodeTargetLevel);
}
if (!myModuleBytecodeTarget.isEmpty()) {
final List<String> moduleNames = new ArrayList<String>(myModuleBytecodeTarget.keySet());
Collections.sort(moduleNames, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
Collections.sort(moduleNames, ALPHA_COMPARATOR);
for (String name : moduleNames) {
final Element moduleElement = new Element("module");
bytecodeTarget.addContent(moduleElement);
moduleElement.setAttribute("name", name);
final Element moduleElement = addChild(bytecodeTarget, MODULE);
moduleElement.setAttribute(NAME, name);
final String value = myModuleBytecodeTarget.get(name);
moduleElement.setAttribute("target", value != null? value : "");
}
@@ -791,6 +728,109 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
}
}
private static void readProfile(Element element, ProcessorConfigProfile profile) {
profile.setName(element.getAttributeValue(NAME, ""));
profile.setEnabled(Boolean.valueOf(element.getAttributeValue(ENABLED, "false")));
final Element srcOutput = element.getChild("sourceOutputDir");
profile.setGeneratedSourcesDirectoryName(srcOutput != null? srcOutput.getAttributeValue(NAME) : null);
profile.clearProcessorOptions();
for (Object optionElement : element.getChildren(OPTION)) {
final Element elem = (Element)optionElement;
final String key = elem.getAttributeValue(NAME);
final String value = elem.getAttributeValue(VALUE);
if (!StringUtil.isEmptyOrSpaces(key) && value != null) {
profile.setOption(key, value);
}
}
profile.clearProcessors();
for (Object procElement : element.getChildren("processor")) {
final String name = ((Element)procElement).getAttributeValue(NAME);
if (StringUtil.isEmptyOrSpaces(name)) {
profile.addProcessor(name);
}
}
final Element pathElement = element.getChild("processorPath");
if (pathElement != null) {
profile.setObtainProcessorsFromClasspath(Boolean.parseBoolean(pathElement.getAttributeValue("useClasspath", "true")));
final StringBuilder pathBuilder = new StringBuilder();
for (Object entry : pathElement.getChildren(ENTRY)) {
final String path = ((Element)entry).getAttributeValue(NAME);
if (!StringUtil.isEmptyOrSpaces(path)) {
if (pathBuilder.length() > 0) {
pathBuilder.append(File.pathSeparator);
}
pathBuilder.append(FileUtil.toSystemDependentName(path));
}
}
profile.setProcessorPath(pathBuilder.toString());
}
profile.clearModuleNames();
for (Object moduleElement : element.getChildren(MODULE)) {
final String name = ((Element)moduleElement).getAttributeValue(NAME);
if (!StringUtil.isEmptyOrSpaces(name)) {
profile.addModuleName(name);
}
}
}
private static void writeProfile(final Element element, ProcessorConfigProfile profile) {
element.setAttribute(NAME, profile.getName());
element.setAttribute(ENABLED, Boolean.toString(profile.isEnabled()));
final String srcDirName = profile.getGeneratedSourcesDirectoryName();
if (srcDirName != null) {
addChild(element, "sourceOutputDir").setAttribute(NAME, srcDirName);
}
final Map<String, String> options = profile.getProcessorOptions();
if (!options.isEmpty()) {
final List<String> keys = new ArrayList<String>(options.keySet());
Collections.sort(keys, ALPHA_COMPARATOR);
for (String key : keys) {
addChild(element, OPTION).setAttribute(NAME, key).setAttribute(VALUE, options.get(key));
}
}
final Set<String> processors = profile.getProcessors();
if (!processors.isEmpty()) {
final List<String> processorList = new ArrayList<String>(processors);
Collections.sort(processorList, ALPHA_COMPARATOR);
for (String proc : processorList) {
addChild(element, "processor").setAttribute(NAME, proc);
}
}
final Element pathElement = addChild(element, "processorPath").setAttribute("useClasspath", Boolean.toString(profile.isObtainProcessorsFromClasspath()));
final String path = profile.getProcessorPath();
if (!StringUtil.isEmpty(path)) {
final StringTokenizer tokenizer = new StringTokenizer(path, File.pathSeparator, false);
while (tokenizer.hasMoreTokens()) {
final String token = tokenizer.nextToken();
addChild(pathElement, ENTRY).setAttribute(NAME, FileUtil.toSystemIndependentName(token));
}
}
final Set<String> moduleNames = profile.getModuleNames();
if (!moduleNames.isEmpty()) {
final List<String> names = new ArrayList<String>(moduleNames);
Collections.sort(names, ALPHA_COMPARATOR);
for (String name : names) {
addChild(element, MODULE).setAttribute(NAME, name);
}
}
}
private static Element addChild(Element parent, final String childName) {
final Element child = new Element(childName);
parent.addContent(child);
return child;
}
@NotNull @NonNls
public String getComponentName() {
return "CompilerConfiguration";
@@ -0,0 +1,210 @@
/*
* Copyright 2000-2012 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.compiler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Eugene Zhuravlev
* Date: 5/25/12
*/
public class ProcessorConfigProfile implements AnnotationProcessingConfiguration {
private String myName = "";
private boolean myEnabled = false;
private boolean myObtainProcessorsFromClasspath = true;
private String myProcessorPath = "";
private final Set<String> myProcessors = new HashSet<String>(); // empty list means all discovered
private final Map<String, String> myProcessorOptions = new HashMap<String, String>(); // key=value map of options
@Nullable
private String myGeneratedSourcesDirectoryName = null; // null means 'auto'
private final Set<String> myModuleNames = new HashSet<String>();
public ProcessorConfigProfile(String name) {
myName = name;
}
public ProcessorConfigProfile(ProcessorConfigProfile profile) {
initFrom(profile);
}
public final void initFrom(ProcessorConfigProfile other) {
myName = other.myName;
myEnabled = other.myEnabled;
myObtainProcessorsFromClasspath = other.myObtainProcessorsFromClasspath;
myProcessorPath = other.myProcessorPath;
myProcessors.clear();
myProcessors.addAll(other.myProcessors);
myProcessorOptions.clear();
myProcessorOptions.putAll(other.myProcessorOptions);
myGeneratedSourcesDirectoryName = other.myGeneratedSourcesDirectoryName;
myModuleNames.clear();
myModuleNames.addAll(other.myModuleNames);
}
public String getName() {
return myName;
}
public void setName(String name) {
myName = name;
}
@Override
public boolean isEnabled() {
return myEnabled;
}
public void setEnabled(boolean enabled) {
myEnabled = enabled;
}
@Override
@NotNull
public String getProcessorPath() {
return myProcessorPath;
}
public void setProcessorPath(@Nullable String processorPath) {
myProcessorPath = processorPath != null? processorPath : "";
}
@Override
public boolean isObtainProcessorsFromClasspath() {
return myObtainProcessorsFromClasspath;
}
public void setObtainProcessorsFromClasspath(boolean value) {
myObtainProcessorsFromClasspath = value;
}
@Override
@Nullable
public String getGeneratedSourcesDirectoryName() {
return myGeneratedSourcesDirectoryName;
}
public void setGeneratedSourcesDirectoryName(@Nullable String generatedSourcesDirectoryName) {
myGeneratedSourcesDirectoryName = generatedSourcesDirectoryName;
}
@NotNull
public Set<String> getModuleNames() {
return myModuleNames;
}
public boolean addModuleName(String name) {
return myModuleNames.add(name);
}
public boolean addModuleNames(Collection<String> names) {
return myModuleNames.addAll(names);
}
public boolean removeModuleName(String name) {
return myModuleNames.remove(name);
}
public boolean removeModuleNames(Collection<String> names) {
return myModuleNames.removeAll(names);
}
public void clearModuleNames() {
myModuleNames.clear();
}
public void clearProcessors() {
myProcessors.clear();
}
public boolean addProcessor(String processor) {
return myProcessors.add(processor);
}
public boolean removeProcessor(String processor) {
return myProcessors.remove(processor);
}
@Override
@NotNull
public Set<String> getProcessors() {
return Collections.unmodifiableSet(myProcessors);
}
@Override
@NotNull
public Map<String, String> getProcessorOptions() {
return Collections.unmodifiableMap(myProcessorOptions);
}
public String setOption(String key, String value) {
return myProcessorOptions.put(key, value);
}
@Nullable
public String getOption(String key) {
return myProcessorOptions.get(key);
}
public void clearProcessorOptions() {
myProcessorOptions.clear();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProcessorConfigProfile profile = (ProcessorConfigProfile)o;
if (myEnabled != profile.myEnabled) return false;
if (myObtainProcessorsFromClasspath != profile.myObtainProcessorsFromClasspath) return false;
if (myGeneratedSourcesDirectoryName != null
? !myGeneratedSourcesDirectoryName.equals(profile.myGeneratedSourcesDirectoryName)
: profile.myGeneratedSourcesDirectoryName != null) {
return false;
}
if (!myModuleNames.equals(profile.myModuleNames)) return false;
if (!myProcessorOptions.equals(profile.myProcessorOptions)) return false;
if (myProcessorPath != null ? !myProcessorPath.equals(profile.myProcessorPath) : profile.myProcessorPath != null) return false;
if (!myProcessors.equals(profile.myProcessors)) return false;
if (!myName.equals(profile.myName)) return false;
return true;
}
@Override
public int hashCode() {
int result = myName.hashCode();
result = 31 * result + (myEnabled ? 1 : 0);
result = 31 * result + (myObtainProcessorsFromClasspath ? 1 : 0);
result = 31 * result + (myProcessorPath != null ? myProcessorPath.hashCode() : 0);
result = 31 * result + myProcessors.hashCode();
result = 31 * result + myProcessorOptions.hashCode();
result = 31 * result + (myGeneratedSourcesDirectoryName != null ? myGeneratedSourcesDirectoryName.hashCode() : 0);
result = 31 * result + myModuleNames.hashCode();
return result;
}
@Override
public String toString() {
return myName;
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.compiler.actions;
import com.intellij.compiler.AnnotationProcessingConfiguration;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.impl.FileSetCompileScope;
import com.intellij.compiler.impl.ModuleCompileScope;
@@ -82,9 +83,12 @@ public class ProcessAnnotationsAction extends CompileActionBase {
final Module module = LangDataKeys.MODULE.getData(dataContext);
final Module moduleContext = LangDataKeys.MODULE_CONTEXT.getData(dataContext);
if (!compilerConfiguration.isAnnotationProcessorsEnabled() ||
(!compilerConfiguration.isObtainProcessorsFromClasspath() && compilerConfiguration.getAnnotationProcessorsMap().isEmpty()) ||
module != null && StringUtil.isEmpty(compilerConfiguration.getAnotationProcessedModules().get(module))) {
if (module == null) {
presentation.setEnabled(false);
return;
}
final AnnotationProcessingConfiguration profile = compilerConfiguration.getAnnotationProcessingConfiguration(module);
if (!profile.isEnabled() || (!profile.isObtainProcessorsFromClasspath() && profile.getProcessors().isEmpty())) {
presentation.setEnabled(false);
return;
}
@@ -169,12 +169,10 @@ public class CompileDriver {
final Pair<VirtualFile, VirtualFile> outputs = new Pair<VirtualFile, VirtualFile>(productionOutput, testOutput);
myGenerationCompilerModuleToOutputDirMap.put(pair, outputs);
}
if (config.isAnnotationProcessorsEnabled()) {
if (config.isAnnotationProcessingEnabled(module)) {
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
if (path != null) {
lookupVFile(lfs, path); // ensure the file is created and added to VFS
}
if (config.getAnnotationProcessingConfiguration(module).isEnabled()) {
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
if (path != null) {
lookupVFile(lfs, path); // ensure the file is created and added to VFS
}
}
}
@@ -395,7 +393,7 @@ public class CompileDriver {
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
final Set<Module> affected = new HashSet<Module>(Arrays.asList(context.getCompileScope().getAffectedModules()));
for (Module module : affected) {
if (!config.isAnnotationProcessingEnabled(module)) {
if (!config.getAnnotationProcessingConfiguration(module).isEnabled()) {
continue;
}
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
@@ -1725,7 +1723,7 @@ public class CompileDriver {
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
if (context.isAnnotationProcessorsEnabled()) {
for (Module module : modules) {
if (config.isAnnotationProcessingEnabled(module)) {
if (config.getAnnotationProcessingConfiguration(module).isEnabled()) {
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
if (path != null) {
outputDirs.add(new File(path));
@@ -2366,7 +2364,7 @@ public class CompileDriver {
modulesWithoutOutputPathSpecified.add(module.getName());
}
}
if (config.isAnnotationProcessorsEnabled() && config.isAnnotationProcessingEnabled(module)) {
if (config.getAnnotationProcessingConfiguration(module).isEnabled()) {
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
if (path == null) {
final CompilerProjectExtension extension = CompilerProjectExtension.getInstance(module.getProject());
@@ -2458,9 +2456,9 @@ public class CompileDriver {
if (chunkModules.size() <= 1) {
continue; // no need to check one-module chunks
}
if (config.isAnnotationProcessorsEnabled()) {
if (!useOutOfProcessBuild()) {
for (Module chunkModule : chunkModules) {
if (config.isAnnotationProcessingEnabled(chunkModule)) {
if (config.getAnnotationProcessingConfiguration(chunkModule).isEnabled()) {
showCyclesNotSupportedForAnnotationProcessors(chunkModules.toArray(new Module[chunkModules.size()]));
return false;
}
@@ -120,7 +120,7 @@ public class AnnotationProcessingCompiler implements TranslatingCompiler{
}
final Module module = context.getModuleByFile(file);
if (module != null) {
if (!myConfig.isAnnotationProcessingEnabled(module)) {
if (!myConfig.getAnnotationProcessingConfiguration(module).isEnabled()) {
return true;
}
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
@@ -15,10 +15,7 @@
*/
package com.intellij.compiler.impl.javaCompiler.javac;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
import com.intellij.compiler.CompilerIOUtil;
import com.intellij.compiler.OutputParser;
import com.intellij.compiler.*;
import com.intellij.compiler.impl.CompilerUtil;
import com.intellij.compiler.impl.javaCompiler.ExternalCompiler;
import com.intellij.compiler.impl.javaCompiler.ModuleChunk;
@@ -283,33 +280,21 @@ public class JavacCompiler extends ExternalCompiler {
annotationProcessorsEnabled = false;
}
if (isAnnotationProcessing) {
final CompilerConfiguration config = CompilerConfiguration.getInstance(chunk.getProject());
final AnnotationProcessingConfiguration config = CompilerConfiguration.getInstance(chunk.getProject()).getAnnotationProcessingConfiguration(chunk.getModules()[0]);
additionalOptions.add("-Xprefer:source");
additionalOptions.add("-implicit:none");
additionalOptions.add("-proc:only");
if (!config.isObtainProcessorsFromClasspath()) {
final String processorPath = config.getProcessorPath();
if (processorPath.length() > 0) {
additionalOptions.add("-processorpath");
additionalOptions.add(FileUtil.toSystemDependentName(processorPath));
}
additionalOptions.add("-processorpath");
additionalOptions.add(FileUtil.toSystemDependentName(processorPath));
}
for (Map.Entry<String, String> entry : config.getAnnotationProcessorsMap().entrySet()) {
for (String processorName : config.getProcessors()) {
additionalOptions.add("-processor");
additionalOptions.add(entry.getKey());
final String options = entry.getValue();
if (options.length() > 0) {
StringTokenizer optionsTokenizer = new StringTokenizer(options, " ", false);
while (optionsTokenizer.hasMoreTokens()) {
final String token = optionsTokenizer.nextToken();
if (token.startsWith("-A")) {
additionalOptions.add(token.substring("-A".length()));
}
else {
additionalOptions.add("-A" + token);
}
}
}
additionalOptions.add(processorName);
}
for (Map.Entry<String, String> entry : config.getProcessorOptions().entrySet()) {
additionalOptions.add("-A" + entry.getKey() + "=" +entry.getValue());
}
}
else {
@@ -17,41 +17,17 @@ package com.intellij.compiler.options;
import com.intellij.compiler.CompileServerManager;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
import com.intellij.compiler.ProcessorConfigProfile;
import com.intellij.compiler.server.BuildManager;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.*;
import com.intellij.ui.table.JBTable;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.EditableModel;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
@@ -59,15 +35,9 @@ import java.util.Map;
* Date: Oct 5, 2009
*/
public class AnnotationProcessorsConfigurable implements SearchableConfigurable, Configurable.NoScroll {
private ProcessedModulesTable myModulesTable;
private final Project myProject;
private JRadioButton myRbClasspath;
private JRadioButton myRbProcessorsPath;
private TextFieldWithBrowseButton myProcessorPathField;
private ProcessorTableModel myProcessorsModel;
private JCheckBox myCbEnableProcessing;
private JBTable myProcessorTable;
private JPanel myProcessorPanel;
private AnnotationProcessorsPanel myMainPanel;
public AnnotationProcessorsConfigurable(final Project project) {
myProject = project;
@@ -95,163 +65,39 @@ public class AnnotationProcessorsConfigurable implements SearchableConfigurable,
}
public JComponent createComponent() {
final JPanel mainPanel = new JPanel(new GridBagLayout());
myCbEnableProcessing = new JCheckBox("Enable annotation processing");
myRbClasspath = new JRadioButton("Obtain processors from project classpath");
myRbProcessorsPath = new JRadioButton("Processor path:");
ButtonGroup group = new ButtonGroup();
group.add(myRbClasspath);
group.add(myRbProcessorsPath);
myProcessorPathField = new TextFieldWithBrowseButton(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createAllButJarContentsDescriptor();
final VirtualFile[] files = FileChooser.chooseFiles(descriptor, myProcessorPathField, myProject, null);
if (files.length > 0) {
final StringBuilder builder = new StringBuilder();
for (VirtualFile file : files) {
if (builder.length() > 0) {
builder.append(File.pathSeparator);
}
builder.append(FileUtil.toSystemDependentName(file.getPath()));
}
myProcessorPathField.setText(builder.toString());
}
}
});
final JPanel processorTablePanel = new JPanel(new BorderLayout());
myProcessorsModel = new ProcessorTableModel();
processorTablePanel.setBorder(IdeBorderFactory.createTitledBorder("Annotation Processors", false));
myProcessorTable = new JBTable(myProcessorsModel);
myProcessorTable.getEmptyText().setText("No processors configured");
myProcessorPanel = ToolbarDecorator.createDecorator(myProcessorTable)
.disableUpAction()
.disableDownAction()
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton anActionButton) {
final TableCellEditor cellEditor = myProcessorTable.getCellEditor();
if (cellEditor != null) {
cellEditor.stopCellEditing();
}
final ProcessorTableModel model = (ProcessorTableModel)myProcessorTable.getModel();
model.addRow();
TableUtil.editCellAt(myProcessorTable, model.getRowCount() - 1, ProcessorTableRow.NAME_COLUMN);
}
})
.createPanel();
processorTablePanel.add(myProcessorPanel, BorderLayout.CENTER);
myModulesTable = new ProcessedModulesTable(myProject);
myModulesTable.setBorder(IdeBorderFactory.createTitledBorder("Processed Modules", false));
final JLabel noteMessage = new JLabel("<html>Source files generated by annotation processors will be stored under the project output directory. " +
"To override this behaviour for certain modules you may specify the directory name in the table below. " +
"If specified, the directory will be created under corresponding module's content root.</html>");
final JLabel warning = new JLabel("<html>WARNING!<br>" +
"All source files located in the generated sources output directory WILL BE EXCLUDED from annotation processing. " +
"If option 'Clear output directory on rebuild' is enabled, " +
"the entire contents of directories specified in the table below WILL BE CLEARED on rebuild.</html>");
warning.setFont(warning.getFont().deriveFont(Font.BOLD));
mainPanel.add(myCbEnableProcessing, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
mainPanel.add(myRbClasspath, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(10, 0, 0, 0), 0, 0));
mainPanel.add(myRbProcessorsPath, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
mainPanel.add(myProcessorPathField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0));
mainPanel.add(processorTablePanel, new GridBagConstraints(0, 3, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
mainPanel.add(noteMessage, new GridBagConstraints(0, 4, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
mainPanel.add(warning, new GridBagConstraints(0, 5, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
mainPanel.add(myModulesTable, new GridBagConstraints(0, 6, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
//mainPanel.add(new AnnotationProcessorsPanel(myProject), new GridBagConstraints(0, 7, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
myRbClasspath.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateEnabledState();
}
});
myProcessorTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
updateEnabledState();
}
}
});
myCbEnableProcessing.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateEnabledState();
}
});
updateEnabledState();
return mainPanel;
}
private void updateEnabledState() {
final boolean enabled = myCbEnableProcessing.isSelected();
final boolean useProcessorpath = !myRbClasspath.isSelected();
myRbClasspath.setEnabled(enabled);
myRbProcessorsPath.setEnabled(enabled);
myProcessorPathField.setEnabled(enabled && useProcessorpath);
final AnActionButton addButton = ToolbarDecorator.findAddButton(myProcessorPanel);
if (addButton != null) {
addButton.setEnabled(enabled);
}
final AnActionButton removeButton = ToolbarDecorator.findRemoveButton(myProcessorPanel);
if (removeButton != null) {
removeButton.setEnabled(enabled && myProcessorTable.getSelectedRow() >= 0);
}
myProcessorTable.setEnabled(enabled);
final JTableHeader header = myProcessorTable.getTableHeader();
if (header != null) {
header.repaint();
}
myModulesTable.getComponent().setEnabled(enabled);
myMainPanel = new AnnotationProcessorsPanel(myProject);
return myMainPanel;
}
public boolean isModified() {
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
if (config.isAnnotationProcessorsEnabled() != myCbEnableProcessing.isSelected()) {
return true;
}
if (config.isObtainProcessorsFromClasspath() != myRbClasspath.isSelected()) {
return true;
}
if (!FileUtil.pathsEqual(config.getProcessorPath(), FileUtil.toSystemIndependentName(myProcessorPathField.getText().trim()))) {
final CompilerConfigurationImpl config = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject);
if (!config.getDefaultProcessorProfile().equals(myMainPanel.getDefaultProfile())) {
return true;
}
final Map<String, String> map = myProcessorsModel.exportToMap();
if (!map.equals(config.getAnnotationProcessorsMap())) {
final Map<String, ProcessorConfigProfile> configProfiles = new java.util.HashMap<String, ProcessorConfigProfile>();
for (ProcessorConfigProfile profile : config.getModuleProcessorProfiles()) {
configProfiles.put(profile.getName(), profile);
}
final List<ProcessorConfigProfile> panelProfiles = myMainPanel.getModuleProfiles();
if (configProfiles.size() != panelProfiles.size()) {
return true;
}
if (!getMarkedModules().equals(config.getAnotationProcessedModules())) {
return true;
for (ProcessorConfigProfile panelProfile : panelProfiles) {
final ProcessorConfigProfile configProfile = configProfiles.get(panelProfile.getName());
if (configProfile == null || !configProfile.equals(panelProfile)) {
return true;
}
}
return false;
}
public void apply() throws ConfigurationException {
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
config.setAnnotationProcessorsEnabled(myCbEnableProcessing.isSelected());
config.setObtainProcessorsFromClasspath(myRbClasspath.isSelected());
config.setProcessorsPath(FileUtil.toSystemIndependentName(myProcessorPathField.getText().trim()));
config.setAnnotationProcessorsMap(myProcessorsModel.exportToMap());
config.setAnotationProcessedModules(getMarkedModules());
final CompilerConfigurationImpl config = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject);
config.setDefaultProcessorProfile(myMainPanel.getDefaultProfile());
config.setModuleProcessorProfiles(myMainPanel.getModuleProfiles());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
CompileServerManager.getInstance().sendReloadRequest(myProject);
@@ -260,161 +106,12 @@ public class AnnotationProcessorsConfigurable implements SearchableConfigurable,
});
}
private Map<Module, String> getMarkedModules() {
final Map<Module, String> result = new HashMap<Module, String>();
for (Pair<Module, String> pair : myModulesTable.getAllModules()) {
result.put(pair.getFirst(), pair.getSecond());
}
return result;
}
public void reset() {
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
myCbEnableProcessing.setSelected(config.isAnnotationProcessorsEnabled());
final boolean obtainFromClasspath = config.isObtainProcessorsFromClasspath();
if (obtainFromClasspath) {
myRbClasspath.setSelected(true);
}
else {
myRbProcessorsPath.setSelected(true);
}
myProcessorPathField.setText(FileUtil.toSystemDependentName(config.getProcessorPath()));
myProcessorsModel.setProcessorMap(config.getAnnotationProcessorsMap());
myModulesTable.removeAllElements();
for (final Module module : ModuleManager.getInstance(myProject).getModules()) {
if (config.isAnnotationProcessingEnabled(module)) {
myModulesTable.addModule(module, config.getGeneratedSourceDirName(module));
}
}
myModulesTable.sort(new Comparator<Module>() {
public int compare(Module o1, Module o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
});
final CompilerConfigurationImpl config = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject);
myMainPanel.initProfiles(config.getDefaultProcessorProfile(), config.getModuleProcessorProfiles());
}
public void disposeUIResources() {
}
private static class ProcessorTableModel extends AbstractTableModel implements EditableModel {
private final java.util.List<ProcessorTableRow> myRows = new ArrayList<ProcessorTableRow>();
public String getColumnName(int column) {
switch (column) {
case ProcessorTableRow.NAME_COLUMN: return "Processor FQ Name";
case ProcessorTableRow.OPTIONS_COLUMN : return "Processor Run Options (space-separated \"key=value\" pairs)";
}
return super.getColumnName(column);
}
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public int getRowCount() {
return myRows.size();
}
public int getColumnCount() {
return 2;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == ProcessorTableRow.NAME_COLUMN || columnIndex == ProcessorTableRow.OPTIONS_COLUMN;
}
public Object getValueAt(int rowIndex, int columnIndex) {
final ProcessorTableRow row = myRows.get(rowIndex);
switch (columnIndex) {
case ProcessorTableRow.NAME_COLUMN: return row.name;
case ProcessorTableRow.OPTIONS_COLUMN : return row.options;
}
return null;
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (aValue != null) {
final ProcessorTableRow row = myRows.get(rowIndex);
switch (columnIndex) {
case ProcessorTableRow.NAME_COLUMN:
row.name = (String)aValue;
break;
case ProcessorTableRow.OPTIONS_COLUMN:
row.options = (String)aValue;
break;
}
}
}
public void removeRow(int idx) {
myRows.remove(idx);
fireTableRowsDeleted(idx, idx);
}
@Override
public void exchangeRows(int oldIndex, int newIndex) {
}
public void addRow() {
myRows.add(new ProcessorTableRow());
final int index = myRows.size() - 1;
fireTableRowsInserted(index, index);
}
public void setProcessorMap(Map<String, String> processorMap) {
clear();
if (processorMap.size() > 0) {
for (Map.Entry<String, String> entry : processorMap.entrySet()) {
myRows.add(new ProcessorTableRow(entry.getKey(), entry.getValue()));
}
Collections.sort(myRows, new Comparator<ProcessorTableRow>() {
public int compare(ProcessorTableRow o1, ProcessorTableRow o2) {
return o1.name.compareToIgnoreCase(o2.name);
}
});
fireTableRowsInserted(0, processorMap.size()-1);
}
}
public void clear() {
final int count = myRows.size();
if (count > 0) {
myRows.clear();
fireTableRowsDeleted(0, count-1);
}
}
public Map<String, String> exportToMap() {
final Map<String, String> map = new HashMap<String, String>();
for (ProcessorTableRow row : myRows) {
if (row.name != null) {
final String name = row.name.trim();
if (name.length() > 0 && !map.containsKey(name)) {
map.put(name, row.options);
}
}
}
return map;
}
}
private static final class ProcessorTableRow {
public static final int NAME_COLUMN = 0;
public static final int OPTIONS_COLUMN = 1;
public String name = "";
public String options = "";
public ProcessorTableRow() {
}
public ProcessorTableRow(String name, String options) {
this.name = name != null? name : "";
this.options = options != null? options : "";
}
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.compiler.options;
import com.intellij.compiler.ProcessorConfigProfile;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ShortcutSet;
@@ -25,10 +26,12 @@ import com.intellij.openapi.ui.InputValidatorEx;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.AnActionButton;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.JBList;
@@ -52,16 +55,20 @@ import java.util.List;
*/
@SuppressWarnings({"unchecked", "UseOfObsoleteCollectionType"})
public class AnnotationProcessorsPanel extends JPanel {
private final Map<String, List<Module>> profiles = new HashMap<String, List<Module>>();
private static final String DEFAULT_PROFILE = "Default";
private final ProcessorConfigProfile myDefaultProfile = new ProcessorConfigProfile("");
private final List<ProcessorConfigProfile> myModuleProfiles = new ArrayList<ProcessorConfigProfile>();
private final Map<String, Module> myAllModulesMap = new HashMap<String, Module>();
private final Project myProject;
private final Tree myTree;
private JPanel myContentPanel;
private final ProcessorProfilePanel myProfilePanel;
private ProcessorConfigProfile mySelectedProfile = null;
public AnnotationProcessorsPanel(Project project) {
super(new BorderLayout());
myProject = project;
loadProfiles();
for (Module module : ModuleManager.getInstance(project).getModules()) {
myAllModulesMap.put(module.getName(), module);
}
myTree = new Tree(new MyTreeModel());
myTree.setRootVisible(false);
final JPanel treePanel =
@@ -70,37 +77,39 @@ public class AnnotationProcessorsPanel extends JPanel {
public void actionPerformed(AnActionEvent e) {
final MyModuleNode node = (MyModuleNode)myTree.getSelectionPath().getLastPathComponent();
final TreePath[] selectedNodes = myTree.getSelectionPaths();
final String key = ((MyProfileNode)node.getParent()).myKey;
final List<String> profileNames = new ArrayList<String>();
profileNames.add(DEFAULT_PROFILE);
profileNames.addAll(profiles.keySet());
profileNames.remove(key);
final JBList list = new JBList(profileNames);
final ProcessorConfigProfile nodeProfile = ((ProfileNode)node.getParent()).myProfile;
final List<ProcessorConfigProfile> profiles = new ArrayList<ProcessorConfigProfile>();
profiles.add(myDefaultProfile);
for (ProcessorConfigProfile profile : myModuleProfiles) {
profiles.add(profile);
}
profiles.remove(nodeProfile);
final JBList list = new JBList(profiles);
final JBPopup popup = JBPopupFactory.getInstance().createListPopupBuilder(list)
.setTitle("Move to")
.setItemChoosenCallback(new Runnable() {
@Override
public void run() {
final Object value = list.getSelectedValue();
if (value instanceof String) {
if (value instanceof ProcessorConfigProfile) {
final ProcessorConfigProfile chosenProfile = (ProcessorConfigProfile)value;
final Module toSelect = (Module)node.getUserObject();
if (selectedNodes != null) {
for (TreePath selectedNode : selectedNodes) {
final Object n = selectedNode.getLastPathComponent();
if (n instanceof MyModuleNode) {
Module module = (Module)((MyModuleNode)n).getUserObject();
if (!DEFAULT_PROFILE.equals(key)) {
profiles.get(key).remove(module);
final Object node = selectedNode.getLastPathComponent();
if (node instanceof MyModuleNode) {
final Module module = (Module)((MyModuleNode)node).getUserObject();
if (nodeProfile != myDefaultProfile) {
nodeProfile.removeModuleName(module.getName());
}
if (!DEFAULT_PROFILE.equals(value)) {
profiles.get(value).add(module);
if (chosenProfile != myDefaultProfile) {
chosenProfile.addModuleName(module.getName());
}
}
}
}
final MyRootNode root = (MyRootNode)myTree.getModel().getRoot();
final RootNode root = (RootNode)myTree.getModel().getRoot();
root.sync();
final DefaultMutableTreeNode node = TreeUtil.findNodeWithObject(root, toSelect);
if (node != null) {
@@ -123,15 +132,13 @@ public class AnnotationProcessorsPanel extends JPanel {
public boolean isEnabled() {
return myTree.getSelectionPath() != null
&& myTree.getSelectionPath().getLastPathComponent() instanceof MyModuleNode
&& !profiles.isEmpty();
&& !myModuleProfiles.isEmpty();
}
}).createPanel();
add(treePanel, BorderLayout.WEST);
myTree.setCellRenderer(new MyCellRenderer());
((MyRootNode)myTree.getModel().getRoot()).sync();
myContentPanel = new JPanel(new BorderLayout());
myTree.addTreeSelectionListener(new TreeSelectionListener() {
String currentProfile = null;
@Override
public void valueChanged(TreeSelectionEvent e) {
final TreePath path = myTree.getSelectionPath();
@@ -140,25 +147,56 @@ public class AnnotationProcessorsPanel extends JPanel {
if (node instanceof MyModuleNode) {
node = ((MyModuleNode)node).getParent();
}
if (node instanceof MyProfileNode) {
if (!StringUtil.equals(currentProfile, ((MyProfileNode)node).myKey)) {
currentProfile = ((MyProfileNode)node).myKey;
myContentPanel.removeAll();
myContentPanel.add(getComponentForProfile(currentProfile), BorderLayout.CENTER);
revalidate();
repaint();
if (node instanceof ProfileNode) {
final ProcessorConfigProfile nodeProfile = ((ProfileNode)node).myProfile;
final ProcessorConfigProfile selectedProfile = mySelectedProfile;
if (nodeProfile != selectedProfile) {
if (selectedProfile != null) {
myProfilePanel.saveTo(selectedProfile);
}
mySelectedProfile = nodeProfile;
myProfilePanel.setProfile(nodeProfile);
}
}
}
}
});
add(myContentPanel, BorderLayout.CENTER);
myProfilePanel = new ProcessorProfilePanel(project);
myProfilePanel.setBorder(IdeBorderFactory.createEmptyBorder(0, 6, 0, 0));
add(myProfilePanel, BorderLayout.CENTER);
}
public void initProfiles(ProcessorConfigProfile defaultProfile, Collection<ProcessorConfigProfile> moduleProfiles) {
myDefaultProfile.initFrom(defaultProfile);
myModuleProfiles.clear();
for (ProcessorConfigProfile profile : moduleProfiles) {
ProcessorConfigProfile copy = new ProcessorConfigProfile("");
copy.initFrom(profile);
myModuleProfiles.add(copy);
}
final RootNode root = (RootNode)myTree.getModel().getRoot();
root.sync();
final DefaultMutableTreeNode node = TreeUtil.findNodeWithObject(root, myDefaultProfile);
if (node != null) {
TreeUtil.selectNode(myTree, node);
}
private JComponent getComponentForProfile(String profile) {
//TODO[jeka] correct panel
return new JLabel(profile, SwingConstants.CENTER);
}
public ProcessorConfigProfile getDefaultProfile() {
final ProcessorConfigProfile selectedProfile = mySelectedProfile;
if (myDefaultProfile == selectedProfile) {
myProfilePanel.saveTo(selectedProfile);
}
return myDefaultProfile;
}
public List<ProcessorConfigProfile> getModuleProfiles() {
final ProcessorConfigProfile selectedProfile = mySelectedProfile;
if (myDefaultProfile != selectedProfile) {
myProfilePanel.saveTo(selectedProfile);
}
return myModuleProfiles;
}
private static void expand(JTree tree) {
@@ -174,48 +212,74 @@ public class AnnotationProcessorsPanel extends JPanel {
while (true);
}
private void loadProfiles() {
//TODO[jeka] init profiles map
}
private class MyTreeModel extends DefaultTreeModel implements EditableTreeModel{
public MyTreeModel() {
super(new MyRootNode());
super(new RootNode());
}
@Override
public TreePath addNode(TreePath parentOrNeighbour) {
final String profile = Messages.showInputDialog(myProject, "Profile name", "Create new profile", null, "", new InputValidatorEx() {
@Override
public boolean checkInput(String inputString) {
return !DEFAULT_PROFILE.equals(inputString) && !profiles.containsKey(inputString) && !StringUtil.isEmpty(inputString);
}
final String newProfileName = Messages.showInputDialog(
myProject, "Profile name", "Create new profile", null, "",
new InputValidatorEx() {
@Override
public boolean checkInput(String inputString) {
if (StringUtil.isEmpty(inputString) ||
Comparing.equal(inputString, myDefaultProfile.getName())) {
return false;
}
for (ProcessorConfigProfile profile : myModuleProfiles) {
if (Comparing.equal(inputString, profile.getName())) {
return false;
}
}
return true;
}
@Override
public boolean canClose(String inputString) {
return checkInput(inputString);
}
@Override
public boolean canClose(String inputString) {
return checkInput(inputString);
}
@Override
public String getErrorText(String inputString) {
if (checkInput(inputString)) return null;
return StringUtil.isEmpty(inputString) ? "Profile name shouldn't be empty"
: "Profile " + inputString + " already exists";
@Override
public String getErrorText(String inputString) {
if (checkInput(inputString)) {
return null;
}
return StringUtil.isEmpty(inputString)
? "Profile name shouldn't be empty"
: "Profile " + inputString + " already exists";
}
});
if (newProfileName != null) {
final ProcessorConfigProfile profile = new ProcessorConfigProfile(newProfileName);
myModuleProfiles.add(profile);
((DataSynchronizable)getRoot()).sync();
final DefaultMutableTreeNode object = TreeUtil.findNodeWithObject((DefaultMutableTreeNode)getRoot(), profile);
if (object != null) {
TreeUtil.selectNode(myTree, object);
}
});
if (profile != null) {
profiles.put(profile, new ArrayList<Module>());
}
((SyncWithMap)getRoot()).sync();
final DefaultMutableTreeNode object = TreeUtil.findNodeWithObject((DefaultMutableTreeNode)getRoot(), profile);
if (object != null) {
TreeUtil.selectNode(myTree, object);
}
return null;
}
@Override
public void removeNode(TreePath parent) {
public void removeNode(TreePath nodePath) {
Object node = nodePath.getLastPathComponent();
if (node instanceof ProfileNode) {
final ProcessorConfigProfile nodeProfile = ((ProfileNode)node).myProfile;
if (nodeProfile != myDefaultProfile) {
if (mySelectedProfile == nodeProfile) {
mySelectedProfile = null;
}
myModuleProfiles.remove(nodeProfile);
((DataSynchronizable)getRoot()).sync();
final DefaultMutableTreeNode object = TreeUtil.findNodeWithObject((DefaultMutableTreeNode)getRoot(), myDefaultProfile);
if (object != null) {
TreeUtil.selectNode(myTree, object);
}
}
}
}
@Override
@@ -225,14 +289,14 @@ public class AnnotationProcessorsPanel extends JPanel {
}
private class MyRootNode extends DefaultMutableTreeNode implements SyncWithMap {
private class RootNode extends DefaultMutableTreeNode implements DataSynchronizable {
@Override
public SyncWithMap sync() {
public DataSynchronizable sync() {
final Vector newKids = new Vector();
for (String key : profiles.keySet()) {
newKids.add(new MyProfileNode(key, this).sync());
newKids.add(new ProfileNode(myDefaultProfile, this, true).sync());
for (ProcessorConfigProfile profile : myModuleProfiles) {
newKids.add(new ProfileNode(profile, this, false).sync());
}
newKids.add(new MyProfileNode(DEFAULT_PROFILE, this).sync());
children = newKids;
((DefaultTreeModel)myTree.getModel()).reload();
expand(myTree);
@@ -240,33 +304,44 @@ public class AnnotationProcessorsPanel extends JPanel {
}
}
private interface SyncWithMap {
SyncWithMap sync();
private interface DataSynchronizable {
DataSynchronizable sync();
}
private class MyProfileNode extends DefaultMutableTreeNode implements SyncWithMap {
private final String myKey;
private class ProfileNode extends DefaultMutableTreeNode implements DataSynchronizable {
private final ProcessorConfigProfile myProfile;
private final boolean myIsDefault;
public MyProfileNode(String key, MyRootNode parent) {
super(key);
public ProfileNode(ProcessorConfigProfile profile, RootNode parent, boolean isDefault) {
super(profile);
setParent(parent);
myKey = key;
myIsDefault = isDefault;
myProfile = profile;
}
@Override
public SyncWithMap sync() {
final List<Module> nodeModules;
if (DEFAULT_PROFILE.equals(myKey)) {
final Module[] allModules = ModuleManager.getInstance(myProject).getSortedModules();
nodeModules = new ArrayList<Module>(Arrays.asList(allModules));
for (List<Module> modules : profiles.values()) {
for (Module module : modules) {
nodeModules.remove(module);
public DataSynchronizable sync() {
final List<Module> nodeModules = new ArrayList<Module>();
if (myIsDefault) {
final Set<String> nonDefaultProfileModules = new HashSet<String>();
for (ProcessorConfigProfile profile : myModuleProfiles) {
nonDefaultProfileModules.addAll(profile.getModuleNames());
}
for (Map.Entry<String, Module> entry : myAllModulesMap.entrySet()) {
if (!nonDefaultProfileModules.contains(entry.getKey())) {
nodeModules.add(entry.getValue());
}
}
} else {
nodeModules = profiles.get(myKey);
}
else {
for (String moduleName : myProfile.getModuleNames()) {
final Module module = myAllModulesMap.get(moduleName);
if (module != null) {
nodeModules.add(module);
}
}
}
Collections.sort(nodeModules, ModuleComparator.INSTANCE);
final Vector vector = new Vector();
for (Module module : nodeModules) {
vector.add(new MyModuleNode(module, this));
@@ -274,32 +349,39 @@ public class AnnotationProcessorsPanel extends JPanel {
children = vector;
return this;
}
}
private class MyModuleNode extends DefaultMutableTreeNode {
public MyModuleNode(Module module, MyProfileNode parent) {
private static class MyModuleNode extends DefaultMutableTreeNode {
public MyModuleNode(Module module, ProfileNode parent) {
super(module);
setParent(parent);
setAllowsChildren(false);
}
}
private class MyCellRenderer extends ColoredTreeCellRenderer {
private static class MyCellRenderer extends ColoredTreeCellRenderer {
private static final Icon MODULE_ICON = IconLoader.getIcon("/nodes/ModuleClosed.png");
@Override
public void customizeCellRenderer(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
if (value instanceof MyProfileNode) {
append(((MyProfileNode)value).myKey);
} else if (value instanceof MyModuleNode) {
public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (value instanceof ProfileNode) {
append(((ProfileNode)value).myProfile.getName());
}
else if (value instanceof MyModuleNode) {
final Module module = (Module)((MyModuleNode)value).getUserObject();
setIcon(IconLoader.getIcon("/nodes/ModuleClosed.png"));
setIcon(MODULE_ICON);
append(module.getName());
}
}
}
private static class ModuleComparator implements Comparator<Module> {
static final ModuleComparator INSTANCE = new ModuleComparator();
@Override
public int compare(Module o1, Module o2) {
return o1.getName().compareTo(o2.getName());
}
}
}
@@ -0,0 +1,454 @@
/*
* Copyright 2000-2012 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.compiler.options;
import com.intellij.compiler.ProcessorConfigProfile;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.*;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.EditableModel;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.util.*;
import java.util.List;
/**
* @author Eugene Zhuravlev
* Date: 5/28/12
*/
public class ProcessorProfilePanel extends JPanel {
private final Project myProject;
private JRadioButton myRbClasspath;
private JRadioButton myRbProcessorsPath;
private TextFieldWithBrowseButton myProcessorPathField;
private JTextField myGeneratedSourcesDirNameField;
private ProcessorTableModel myProcessorsModel;
private JCheckBox myCbEnableProcessing;
private JBTable myProcessorTable;
private JBTable myOptionsTable;
private JPanel myProcessorPanel;
private JPanel myOptionsPanel;
private OptionsTableModel myOptionsModel;
public ProcessorProfilePanel(Project project) {
super(new GridBagLayout());
myProject = project;
myCbEnableProcessing = new JCheckBox("Enable annotation processing");
myRbClasspath = new JRadioButton("Obtain processors from project classpath");
myRbProcessorsPath = new JRadioButton("Processor path:");
ButtonGroup group = new ButtonGroup();
group.add(myRbClasspath);
group.add(myRbProcessorsPath);
myProcessorPathField = new TextFieldWithBrowseButton(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createAllButJarContentsDescriptor();
final VirtualFile[] files = FileChooser.chooseFiles(descriptor, myProcessorPathField, myProject, null);
if (files.length > 0) {
final StringBuilder builder = new StringBuilder();
for (VirtualFile file : files) {
if (builder.length() > 0) {
builder.append(File.pathSeparator);
}
builder.append(FileUtil.toSystemDependentName(file.getPath()));
}
myProcessorPathField.setText(builder.toString());
}
}
});
final JPanel processorTablePanel = new JPanel(new BorderLayout());
myProcessorsModel = new ProcessorTableModel();
processorTablePanel.setBorder(IdeBorderFactory.createTitledBorder("Annotation Processors", false));
myProcessorTable = new JBTable(myProcessorsModel);
myProcessorTable.getEmptyText().setText("Compiler will run all automatically discovered processors");
myProcessorPanel = createTablePanel(myProcessorTable);
processorTablePanel.add(myProcessorPanel, BorderLayout.CENTER);
final JPanel optionsTablePanel = new JPanel(new BorderLayout());
myOptionsModel = new OptionsTableModel();
optionsTablePanel.setBorder(IdeBorderFactory.createTitledBorder("Annotation Processor options", false));
myOptionsTable = new JBTable(myOptionsModel);
myOptionsTable.getEmptyText().setText("No processor-specific options configured");
myOptionsPanel = createTablePanel(myOptionsTable);
optionsTablePanel.add(myOptionsPanel, BorderLayout.CENTER);
myGeneratedSourcesDirNameField = new JTextField();
final JLabel warning = new JLabel("<html>WARNING!<br>" +
/*"All source files located in the generated sources output directory WILL BE EXCLUDED from annotation processing. " +*/
"If option 'Clear output directory on rebuild' is enabled, " +
"the entire contents of directories specified in the table below WILL BE CLEARED on rebuild.</html>");
warning.setFont(warning.getFont().deriveFont(Font.BOLD));
add(myCbEnableProcessing,
new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
add(myRbClasspath,
new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(10, 0, 0, 0), 0, 0));
add(myRbProcessorsPath,
new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
add(myProcessorPathField,
new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0));
final JLabel noteMessage = new JLabel("<html>Source files generated by annotation processors will be stored under the project output directory. " +
"To override this behaviour for this profile you may specify the directory name in the field below. " +
"If specified, the directory will be created under corresponding module's content root.</html>");
add(noteMessage,
new GridBagConstraints(0, 3, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
add(new JLabel("Directory name:"),
new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
add(myGeneratedSourcesDirNameField,
new GridBagConstraints(1, 4, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
add(processorTablePanel,
new GridBagConstraints(0, 5, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
add(optionsTablePanel,
new GridBagConstraints(0, 6, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
add(warning,
new GridBagConstraints(0, 7, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
myRbClasspath.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateEnabledState();
}
});
myProcessorTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
updateEnabledState();
}
}
});
myCbEnableProcessing.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateEnabledState();
}
});
updateEnabledState();
}
public void setProfile(ProcessorConfigProfile config) {
myCbEnableProcessing.setSelected(config.isEnabled());
(config.isObtainProcessorsFromClasspath()? myRbClasspath : myRbProcessorsPath).setSelected(true);
myProcessorPathField.setText(FileUtil.toSystemDependentName(config.getProcessorPath()));
final String srcDirName = config.getGeneratedSourcesDirectoryName();
myGeneratedSourcesDirNameField.setText(srcDirName != null? srcDirName.trim() : "");
myProcessorsModel.setProcessors(config.getProcessors());
myOptionsModel.setOptions(config.getProcessorOptions());
updateEnabledState();
}
public void saveTo(ProcessorConfigProfile profile) {
profile.setEnabled(myCbEnableProcessing.isSelected());
profile.setObtainProcessorsFromClasspath(myRbClasspath.isSelected());
profile.setProcessorPath(myProcessorPathField.getText().trim());
final String dirName = myGeneratedSourcesDirNameField.getText().trim();
profile.setGeneratedSourcesDirectoryName(StringUtil.isEmpty(dirName)? null : dirName);
profile.clearProcessors();
for (String processor : myProcessorsModel.getProcessors()) {
profile.addProcessor(processor);
}
profile.clearProcessorOptions();
for (Map.Entry<String, String> entry : myOptionsModel.getOptions().entrySet()) {
profile.setOption(entry.getKey(), entry.getValue());
}
}
private static JPanel createTablePanel(final JBTable table) {
return ToolbarDecorator.createDecorator(table)
.disableUpAction()
.disableDownAction()
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton anActionButton) {
final TableCellEditor cellEditor = table.getCellEditor();
if (cellEditor != null) {
cellEditor.stopCellEditing();
}
final TableModel model = table.getModel();
((EditableModel)model).addRow();
TableUtil.editCellAt(table, model.getRowCount() - 1, 0);
}
})
.createPanel();
}
private void updateEnabledState() {
final boolean enabled = myCbEnableProcessing.isSelected();
final boolean useProcessorpath = !myRbClasspath.isSelected();
myRbClasspath.setEnabled(enabled);
myRbProcessorsPath.setEnabled(enabled);
myProcessorPathField.setEnabled(enabled && useProcessorpath);
updateTable(myProcessorPanel, myProcessorTable, enabled);
updateTable(myOptionsPanel, myOptionsTable, enabled);
myGeneratedSourcesDirNameField.setEnabled(enabled);
}
private static void updateTable(final JPanel tablePanel, final JBTable table, boolean enabled) {
final AnActionButton addButton = ToolbarDecorator.findAddButton(tablePanel);
if (addButton != null) {
addButton.setEnabled(enabled);
}
final AnActionButton removeButton = ToolbarDecorator.findRemoveButton(tablePanel);
if (removeButton != null) {
removeButton.setEnabled(enabled && table.getSelectedRow() >= 0);
}
table.setEnabled(enabled);
final JTableHeader header = table.getTableHeader();
if (header != null) {
header.repaint();
}
}
private static class OptionsTableModel extends AbstractTableModel implements EditableModel {
private final java.util.List<KeyValuePair> myRows = new ArrayList<KeyValuePair>();
public String getColumnName(int column) {
switch (column) {
case 0: return "Option Name";
case 1: return "Value";
}
return super.getColumnName(column);
}
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public int getRowCount() {
return myRows.size();
}
public int getColumnCount() {
return 2;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 0 || columnIndex == 1;
}
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0: return myRows.get(rowIndex).key;
case 1: return myRows.get(rowIndex).value;
}
return null;
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (aValue != null) {
switch (columnIndex) {
case 0:
myRows.get(rowIndex).key = (String)aValue;
break;
case 1:
myRows.get(rowIndex).value = (String)aValue;
break;
}
}
}
public void removeRow(int idx) {
myRows.remove(idx);
fireTableRowsDeleted(idx, idx);
}
@Override
public void exchangeRows(int oldIndex, int newIndex) {
}
public void addRow() {
myRows.add(new KeyValuePair());
final int index = myRows.size() - 1;
fireTableRowsInserted(index, index);
}
public void setOptions(Map<String, String> options) {
clear();
if (!options.isEmpty()) {
for (Map.Entry<String, String> entry : options.entrySet()) {
myRows.add(new KeyValuePair(entry.getKey(), entry.getValue()));
}
Collections.sort(myRows, new Comparator<KeyValuePair>() {
@Override
public int compare(KeyValuePair o1, KeyValuePair o2) {
return o1.key.compareToIgnoreCase(o2.key);
}
});
fireTableRowsInserted(0, options.size()-1);
}
}
public void clear() {
final int count = myRows.size();
if (count > 0) {
myRows.clear();
fireTableRowsDeleted(0, count-1);
}
}
public Map<String, String> getOptions() {
final Map<String, String> map = new java.util.HashMap<String, String>();
for (KeyValuePair pair : myRows) {
map.put(pair.key.trim(), pair.value.trim());
}
map.remove("");
return map;
}
private static final class KeyValuePair {
String key;
String value;
KeyValuePair() {
this("", "");
}
KeyValuePair(String key, String value) {
this.key = key;
this.value = value;
}
}
}
private static class ProcessorTableModel extends AbstractTableModel implements EditableModel {
private final List<String> myRows = new ArrayList<String>();
public String getColumnName(int column) {
switch (column) {
case 0: return "Processor FQ Name";
}
return super.getColumnName(column);
}
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public int getRowCount() {
return myRows.size();
}
public int getColumnCount() {
return 1;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 0;
}
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0: return myRows.get(rowIndex);
}
return null;
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (aValue != null) {
switch (columnIndex) {
case 0:
myRows.set(rowIndex, (String)aValue);
break;
}
}
}
public void removeRow(int idx) {
myRows.remove(idx);
fireTableRowsDeleted(idx, idx);
}
@Override
public void exchangeRows(int oldIndex, int newIndex) {
}
public void addRow() {
myRows.add("");
final int index = myRows.size() - 1;
fireTableRowsInserted(index, index);
}
public void setProcessors(Collection<String> processors) {
clear();
if (!processors.isEmpty()) {
for (String processor : processors) {
myRows.add(processor);
}
Collections.sort(myRows, new Comparator<String>() {
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
fireTableRowsInserted(0, processors.size()-1);
}
}
public void clear() {
final int count = myRows.size();
if (count > 0) {
myRows.clear();
fireTableRowsDeleted(0, count-1);
}
}
public Collection<String> getProcessors() {
final Set<String> set = new HashSet<String>();
for (String row : myRows) {
if (row != null) {
set.add(row.trim());
}
}
set.remove("");
return set;
}
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2012 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.compiler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Set;
/**
* @author Eugene Zhuravlev
* Date: 5/27/12
*/
public interface AnnotationProcessingConfiguration {
boolean isEnabled();
@NotNull
String getProcessorPath();
@Nullable
String getGeneratedSourcesDirectoryName();
@NotNull
Set<String> getProcessors();
@NotNull
Map<String, String> getProcessorOptions();
boolean isObtainProcessorsFromClasspath();
}
@@ -19,10 +19,9 @@ package com.intellij.compiler;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
public abstract class CompilerConfiguration {
// need this flag for profiling purposes. In production code is always set to 'true'
public static final boolean MAKE_ENABLED = true;
@@ -35,6 +34,14 @@ public abstract class CompilerConfiguration {
public abstract void setBytecodeTargetLevel(Module module, String level);
@NotNull
public abstract AnnotationProcessingConfiguration getAnnotationProcessingConfiguration(Module module);
/**
* @return true if exists at least one enabled annotation processing profile
*/
public abstract boolean isAnnotationProcessorsEnabled();
public static CompilerConfiguration getInstance(Project project) {
return project.getComponent(CompilerConfiguration.class);
}
@@ -50,28 +57,4 @@ public abstract class CompilerConfiguration {
public abstract boolean isAddNotNullAssertions();
public abstract void setAddNotNullAssertions(boolean enabled);
public abstract boolean isAnnotationProcessorsEnabled();
public abstract void setAnnotationProcessorsEnabled(boolean enableAnnotationProcessors);
public abstract boolean isObtainProcessorsFromClasspath();
public abstract void setObtainProcessorsFromClasspath(boolean obtainProcessorsFromClasspath);
public abstract String getProcessorPath();
public abstract void setProcessorsPath(String processorsPath);
public abstract Map<String, String> getAnnotationProcessorsMap();
public abstract void setAnnotationProcessorsMap(Map<String, String> map);
public abstract void setAnotationProcessedModules(Map<Module, String> modules);
public abstract Map<Module, String> getAnotationProcessedModules();
public abstract boolean isAnnotationProcessingEnabled(Module module);
public abstract String getGeneratedSourceDirName(Module module);
}
@@ -216,8 +216,8 @@ public class CompilerPaths {
public static String getAnnotationProcessorsGenerationPath(Module module) {
final CompilerConfiguration config = CompilerConfiguration.getInstance(module.getProject());
final String sourceDirName = config.getGeneratedSourceDirName(module);
if (sourceDirName != null && sourceDirName.length() > 0) {
final String sourceDirName = config.getAnnotationProcessingConfiguration(module).getGeneratedSourcesDirectoryName();
if (!StringUtil.isEmpty(sourceDirName)) {
final String[] roots = ModuleRootManager.getInstance(module).getContentRootUrls();
if (roots.length == 0) {
return null;
@@ -46,6 +46,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler
private final CanceledStatus myCancelStatus;
private float myDone = -1.0f;
private EventDispatcher<BuildListener> myListeners = EventDispatcher.create(BuildListener.class);
private Map<Module, AnnotationProcessingProfile> myAnnotationProcessingProfileMap;
public CompileContext(CompileScope scope,
ProjectDescriptor pd, boolean isMake,
@@ -103,6 +104,32 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler
myListeners.removeListener(listener);
}
@NotNull
public AnnotationProcessingProfile getAnnotationProcessingProfile(Module module) {
final CompilerConfiguration compilerConfig = getProject().getCompilerConfiguration();
Map<Module, AnnotationProcessingProfile> map = myAnnotationProcessingProfileMap;
if (map == null) {
map = new HashMap<Module, AnnotationProcessingProfile>();
final Map<String, Module> namesMap = new HashMap<String, Module>();
for (Module m : getProject().getModules().values()) {
namesMap.put(m.getName(), m);
}
if (!namesMap.isEmpty()) {
for (AnnotationProcessingProfile profile : compilerConfig.getModuleAnnotationProcessingProfiles()) {
for (String name : profile.getProcessModule()) {
final Module mod = namesMap.get(name);
if (mod != null) {
map.put(mod, profile);
}
}
}
}
myAnnotationProcessingProfileMap = map;
}
final AnnotationProcessingProfile profile = map.get(module);
return profile != null? profile : compilerConfig.getDefaultAnnotationProcessingProfile();
}
public void markDirty(final File file) throws IOException {
final RootDescriptor descriptor = getModuleAndRoot(file);
if (descriptor != null) {
@@ -416,6 +416,15 @@ public class IncProjectBuilder {
throw new ProjectBuildException(e);
}
finally {
final Collection<RootDescriptor> tempRoots = context.getRootsIndex().clearTempRoots();
if (!tempRoots.isEmpty()) {
final Set<File> rootFiles = new HashSet<File>();
for (RootDescriptor rd : tempRoots) {
rootFiles.add(rd.root);
context.getProjectDescriptor().fsState.clearRecompile(rd);
}
FileUtil.asyncDelete(rootFiles);
}
try {
// restore deleted paths that were not procesesd by 'integrate'
@@ -41,13 +41,13 @@ public class ModuleRootsIndex {
}
for (String r : module.getSourceRoots()) {
final File root = new File(FileUtil.toCanonicalPath(r));
final RootDescriptor descriptor = new RootDescriptor(moduleName, root, false, generatedRoots.contains(r));
final RootDescriptor descriptor = new RootDescriptor(moduleName, root, false, generatedRoots.contains(r), false);
myRootToModuleMap.put(root, descriptor);
moduleRoots.add(descriptor);
}
for (String r : module.getTestRoots()) {
final File root = new File(FileUtil.toCanonicalPath(r));
final RootDescriptor descriptor = new RootDescriptor(moduleName, root, true, generatedRoots.contains(r));
final RootDescriptor descriptor = new RootDescriptor(moduleName, root, true, generatedRoots.contains(r), false);
myRootToModuleMap.put(root, descriptor);
moduleRoots.add(descriptor);
}
@@ -79,7 +79,7 @@ public class ModuleRootsIndex {
}
@NotNull
public RootDescriptor associateRoot(File root, Module module, boolean isTestRoot, final boolean isForGeneratedSources) {
public RootDescriptor associateRoot(File root, Module module, boolean isTestRoot, final boolean isForGeneratedSources, final boolean isTemp) {
final RootDescriptor d = myRootToModuleMap.get(root);
if (d != null) {
return d;
@@ -89,12 +89,29 @@ public class ModuleRootsIndex {
moduleRoots = new ArrayList<RootDescriptor>();
myModuleToRootsMap.put(module, moduleRoots);
}
final RootDescriptor descriptor = new RootDescriptor(module.getName(), root, isTestRoot, isForGeneratedSources);
final RootDescriptor descriptor = new RootDescriptor(module.getName(), root, isTestRoot, isForGeneratedSources, isTemp);
myRootToModuleMap.put(root, descriptor);
moduleRoots.add(descriptor);
return descriptor;
}
@NotNull
public Collection<RootDescriptor> clearTempRoots() {
final Set<RootDescriptor> toRemove = new HashSet<RootDescriptor>();
for (Iterator<Map.Entry<File, RootDescriptor>> iterator = myRootToModuleMap.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<File, RootDescriptor> entry = iterator.next();
final RootDescriptor rd = entry.getValue();
if (rd.isTemp) {
toRemove.add(rd);
iterator.remove();
}
}
for (Map.Entry<Module, List<RootDescriptor>> entry : myModuleToRootsMap.entrySet()) {
entry.getValue().removeAll(toRemove);
}
return toRemove;
}
@Nullable
public RootDescriptor getModuleAndRoot(File file) {
File current = file;
@@ -15,12 +15,14 @@ public final class RootDescriptor {
public final File root;
public final boolean isTestRoot;
public final boolean isGeneratedSources;
public final boolean isTemp;
public RootDescriptor(@NotNull final String moduleName, @NotNull File root, boolean isTestRoot, boolean isGenerated) {
public RootDescriptor(@NotNull final String moduleName, @NotNull File root, boolean isTestRoot, boolean isGenerated, boolean isTemp) {
this.module = moduleName;
this.root = root;
this.isTestRoot = isTestRoot;
this.isGeneratedSources = isGenerated;
this.isTemp = isTemp;
}
@Override
@@ -60,7 +60,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
public static final boolean USE_EMBEDDED_JAVAC = System.getProperty(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION) == null;
private static final Key<Integer> JAVA_COMPILER_VERSION_KEY = Key.create("_java_compiler_version_");
private static final Set<String> FILTERED_OPTIONS = new HashSet<String>(Arrays.<String>asList(
"-target"
"-target", "-proc:none", "-proc:only"
));
private static final Set<String> FILTERED_SINGLE_OPTIONS = new HashSet<String>(Arrays.<String>asList(
"-g", "-deprecation", "-nowarn", "-verbose"
@@ -89,26 +89,32 @@ public class JavaBuilder extends ModuleLevelBuilder {
//add here class processors in the sequence they should be executed
myClassProcessors.add(new ClassPostProcessor() {
public void process(CompileContext context, OutputFileObject out) {
final Callbacks.Backend callback = DELTA_MAPPINGS_CALLBACK_KEY.get(context);
if (callback != null) {
final OutputFileObject.Content content = out.getContent();
final File srcFile = out.getSourceFile();
if (srcFile != null && content != null) {
final String outputPath = FileUtil.toSystemIndependentName(out.getFile().getPath());
final String sourcePath = FileUtil.toSystemIndependentName(srcFile.getPath());
final RootDescriptor moduleAndRoot = context.getModuleAndRoot(srcFile);
final BuildDataManager dataManager = context.getDataManager();
if (moduleAndRoot != null) {
final OutputFileObject.Content content = out.getContent();
final File srcFile = out.getSourceFile();
if (srcFile != null && content != null) {
final String outputPath = FileUtil.toSystemIndependentName(out.getFile().getPath());
final String sourcePath = FileUtil.toSystemIndependentName(srcFile.getPath());
final RootDescriptor moduleAndRoot = context.getModuleAndRoot(srcFile);
final BuildDataManager dataManager = context.getDataManager();
boolean isTemp = false;
if (moduleAndRoot != null) {
isTemp = moduleAndRoot.isTemp;
if (!isTemp) {
try {
final String moduleName = moduleAndRoot.module;
dataManager.getSourceToOutputMap(moduleName, context.isCompilingTests()).appendData(sourcePath, outputPath);
dataManager.getSourceToOutputMap(moduleAndRoot.module, context.isCompilingTests()).appendData(sourcePath, outputPath);
}
catch (Exception e) {
context.processMessage(new CompilerMessage(BUILDER_NAME, e));
}
}
final ClassReader reader = new ClassReader(content.getBuffer(), content.getOffset(), content.getLength());
callback.associate(outputPath, sourcePath, reader);
}
out.setTemp(isTemp);
if (!isTemp) {
final Callbacks.Backend callback = DELTA_MAPPINGS_CALLBACK_KEY.get(context);
if (callback != null) {
final ClassReader reader = new ClassReader(content.getBuffer(), content.getOffset(), content.getLength());
callback.associate(outputPath, sourcePath, reader);
}
}
}
}
@@ -124,17 +130,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
return "Java Builder";
}
private static final Key<Set<File>> TEMPORARY_SOURCE_ROOTS_KEY = Key.create("_additional_source_roots_");
public static void addTempSourcePathRoot(CompileContext context, File root) {
Set<File> roots = TEMPORARY_SOURCE_ROOTS_KEY.get(context);
if (roots == null) {
roots = new HashSet<File>();
TEMPORARY_SOURCE_ROOTS_KEY.set(context, roots);
}
roots.add(root);
}
public ExitCode build(final CompileContext context, final ModuleChunk chunk) throws ProjectBuildException {
try {
final Set<File> filesToCompile = new HashSet<File>();
@@ -282,7 +277,15 @@ public class JavaBuilder extends ModuleLevelBuilder {
try {
if (hasSourcesToCompile) {
exitCode = ExitCode.OK;
final Set<File> sourcePath = TEMPORARY_SOURCE_ROOTS_KEY.get(context, Collections.<File>emptySet());
final Set<File> tempRootsSourcePath = new HashSet<File>();
final ModuleRootsIndex index = context.getRootsIndex();
for (Module module : chunk.getModules()) {
for (RootDescriptor rd : index.getModuleRoots(module)) {
if (rd.isTemp) {
tempRootsSourcePath.add(rd.root);
}
}
}
final String chunkName = getChunkPresentableName(chunk);
context.processMessage(new ProgressMessage("Compiling java [" + chunkName + "]"));
@@ -291,7 +294,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
boolean compiledOk = true;
if (filesCount > 0) {
LOG.info("Compiling " + filesCount + " java files; module: " + chunkName);
compiledOk = compileJava(chunk, files, classpath, platformCp, sourcePath, outs, context, diagnosticSink, outputSink);
compiledOk = compileJava(chunk, files, classpath, platformCp, tempRootsSourcePath, outs, context, diagnosticSink, outputSink);
}
context.checkCanceled();
@@ -362,13 +365,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
}
if (exitCode != ExitCode.ADDITIONAL_PASS_REQUIRED) {
final Set<File> tempRoots = TEMPORARY_SOURCE_ROOTS_KEY.get(context);
TEMPORARY_SOURCE_ROOTS_KEY.set(context, null);
if (tempRoots != null && tempRoots.size() > 0) {
FileUtil.asyncDelete(tempRoots);
}
}
return exitCode;
}
@@ -399,6 +395,9 @@ public class JavaBuilder extends ModuleLevelBuilder {
DiagnosticOutputConsumer diagnosticSink,
final OutputFileConsumer outputSink) throws Exception {
final List<String> options = getCompilationOptions(context, chunk);
if (context.errorsDetected()) {
return true;
}
final ClassProcessingConsumer classesConsumer = new ClassProcessingConsumer(context, outputSink);
try {
final boolean rc;
@@ -670,9 +669,57 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
}
AnnotationProcessingProfile profile = null;
for (Module module : chunk.getModules()) {
if (profile == null) {
profile = context.getAnnotationProcessingProfile(module);
}
else {
final AnnotationProcessingProfile profile2 = context.getAnnotationProcessingProfile(module);
if (profile2 != profile) {
String message = "Modules in cycle [" + getChunkPresentableName(chunk) + "] must use the same annotation processing profile";
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, message));
}
}
}
if (profile != null && profile.isEnabled()) {
// configuring annotation processing
if (!profile.getObtainProcessorsFromClasspath()) {
final String processorsPath = profile.getProcessorsPath();
options.add("-processorpath");
options.add(processorsPath == null? "" : FileUtil.toSystemDependentName(processorsPath.trim()));
}
for (String procFQName : profile.getProcessors()) {
options.add("-processor");
options.add(procFQName);
}
for (Map.Entry<String, String> optionEntry : profile.getProcessorsOptions().entrySet()) {
options.add("-A" + optionEntry.getKey() + "=" + optionEntry.getValue());
}
final File srcOutput = getGeneratedSourcesOutputDirectory(context, chunk, profile.getGeneratedSourcesDirName());
if (srcOutput != null) {
srcOutput.mkdirs();
options.add("-s");
options.add(srcOutput.getPath());
}
}
else {
options.add("-proc:none");
}
return options;
}
@Nullable
private static File getGeneratedSourcesOutputDirectory(CompileContext context, ModuleChunk chunk, String name) {
// todo: support multiple outputs for module chunk
return context.getProjectPaths().getAnnotationProcessorGeneratedSourcesOutputDir(chunk.getModules().iterator().next(), context.isCompilingTests(), name);
}
private static boolean isEncodingSet(List<String> options) {
for (String option : options) {
if ("-encoding".equals(option)) {
@@ -718,7 +765,8 @@ public class JavaBuilder extends ModuleLevelBuilder {
//options.add("-verbose");
final Project project = context.getProject();
final Map<String, String> javacOpts = project.getCompilerConfiguration().getJavacOptions();
final CompilerConfiguration compilerConfig = project.getCompilerConfiguration();
final Map<String, String> javacOpts = compilerConfig.getJavacOptions();
final boolean debugInfo = !"false".equals(javacOpts.get("DEBUGGING_INFO"));
final boolean nowarn = "true".equals(javacOpts.get("GENERATE_NO_WARNINGS"));
final boolean deprecation = !"false".equals(javacOpts.get("DEPRECATION"));
@@ -778,6 +826,9 @@ public class JavaBuilder extends ModuleLevelBuilder {
private static void instrumentNotNull(CompileContext context, OutputFilesSink sink, final InstrumentationClassFinder finder) {
for (final OutputFileObject fileObject : sink.getFileObjects()) {
final OutputFileObject.Content originalContent = fileObject.getContent();
if (originalContent == null || !JavaFileObject.Kind.CLASS.equals(fileObject.getKind())) {
continue;
}
final ClassReader reader = new ClassReader(originalContent.getBuffer(), originalContent.getOffset(), originalContent.getLength());
final int version = getClassFileVersion(reader);
if (version >= Opcodes.V1_5) {
@@ -822,7 +873,9 @@ public class JavaBuilder extends ModuleLevelBuilder {
final Map<String, OutputFileObject> compiledClassNames = new HashMap<String, OutputFileObject>();
for (OutputFileObject fileObject : outputSink.getFileObjects()) {
compiledClassNames.put(fileObject.getClassName(), fileObject);
if (JavaFileObject.Kind.CLASS.equals(fileObject.getKind())) {
compiledClassNames.put(fileObject.getClassName(), fileObject);
}
}
final MyNestedFormLoader nestedFormsLoader =
@@ -19,7 +19,7 @@ import java.util.*;
*/
class OutputFilesSink implements OutputFileConsumer {
private final CompileContext myContext;
private final Set<File> mySuccessfullyCompiled = new HashSet<File>();
private final Set<File> mySuccessfullyCompiled = new LinkedHashSet<File>();
private final Set<File> myProblematic = new HashSet<File>();
private final List<OutputFileObject> myFileObjects = new ArrayList<OutputFileObject>();
private final Map<String, OutputFileObject> myCompiledClasses = new HashMap<String, OutputFileObject>();
@@ -113,7 +113,7 @@ class OutputFilesSink implements OutputFileConsumer {
}
final File source = fileObject.getSourceFile();
if (source != null && !myProblematic.contains(source)) {
if (!fileObject.isTemp() && source != null && !myProblematic.contains(source)) {
mySuccessfullyCompiled.add(source);
final String className = fileObject.getClassName();
if (className != null) {
@@ -19,7 +19,7 @@ public class JavacMain {
"-d", "-classpath", "-cp", "-bootclasspath"
));
private static final Set<String> FILTERED_SINGLE_OPTIONS = new HashSet<String>(Arrays.<String>asList(
"-verbose", "-proc:none", "-implicit:class", "-implicit:none"
"-verbose", "-proc:only", "-implicit:class", "-implicit:none"
));
public static boolean compile(Collection<String> options,
@@ -71,12 +71,12 @@ public class JavacMain {
out, fileManager, outConsumer, _options, null, fileManager.toJavaFileObjects(sources)
);
if (!IS_VM_6_VERSION) {
// Do not add the processor for JDK 1.6 because of the bugs in javac
// The processor's presence may lead to NPE and resolve bugs in compiler
final JavacASTAnalyser analyzer = new JavacASTAnalyser(outConsumer, shouldSuppressAnnotationProcessing(options));
task.setProcessors(Collections.singleton(analyzer));
}
//if (!IS_VM_6_VERSION) { //todo!
// // Do not add the processor for JDK 1.6 because of the bugs in javac
// // The processor's presence may lead to NPE and resolve bugs in compiler
// final JavacASTAnalyser analyzer = new JavacASTAnalyser(outConsumer, !annotationProcessingEnabled);
// task.setProcessors(Collections.singleton(analyzer));
//}
return task.call();
}
catch(IllegalArgumentException e) {
@@ -88,13 +88,13 @@ public class JavacMain {
return false;
}
private static boolean shouldSuppressAnnotationProcessing(final Collection<String> options) {
private static boolean isAnnotationProcessingEnabled(final Collection<String> options) {
for (String option : options) {
if ("-proc:none".equals(option)) {
return true;
return false;
}
}
return false;
return true;
}
private static Collection<String> prepareOptions(final Collection<String> options) {
@@ -25,6 +25,7 @@ public final class OutputFileObject extends SimpleJavaFileObject {
@Nullable private final URI mySourceUri;
private volatile Content myContent;
private final File mySourceFile;
public boolean myIsTemp = false;
public OutputFileObject(@NotNull JavacFileManager.Context context, @Nullable File outputRoot, String relativePath, @NotNull File file, @NotNull Kind kind, @Nullable String className, @Nullable final URI sourceUri) {
this(context, outputRoot, relativePath, file, kind, className, sourceUri, null);
@@ -42,6 +43,14 @@ public final class OutputFileObject extends SimpleJavaFileObject {
mySourceFile = srcUri != null? Utils.convertToFile(srcUri) : null;
}
public boolean isTemp() {
return myIsTemp;
}
public void setTemp(boolean isTemp) {
myIsTemp = isTemp;
}
@Nullable
public File getOutputRoot() {
return myOutputRoot;
@@ -10,17 +10,21 @@ class CompilerConfiguration {
Map<String, String> javacOptions = [:]
boolean clearOutputDirectoryOnRebuild = true
boolean addNotNullAssertions = true
AnnotationProcessingConfiguration annotationProcessing = new AnnotationProcessingConfiguration()
AnnotationProcessingProfile defaultAnnotationProcessingProfile = new AnnotationProcessingProfile()
Collection<AnnotationProcessingProfile> moduleAnnotationProcessingProfiles = []
BytecodeTargetConfiguration bytecodeTarget = new BytecodeTargetConfiguration()
CompilerExcludes excludes = new CompilerExcludes()
}
class AnnotationProcessingConfiguration {
class AnnotationProcessingProfile {
String name = ""
boolean enabled = false
boolean obtainProcessorsFromClasspath = true
String processorsPath
List<String> processors = []
Map<String, String> processorsOptions = [:]
Map<String, String> processModule = [:]
String generatedSourcesDirName = ""
List<String> processModule = []
}
class BytecodeTargetConfiguration {
@@ -1,6 +1,7 @@
package org.jetbrains.jps;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -12,6 +13,7 @@ import java.util.*;
* Date: 9/30/11
*/
public class ProjectPaths {
private static final String DEFAULT_GENERATED_DIR_NAME = "generated";
@NotNull
private final Project myProject;
@Nullable
@@ -236,6 +238,36 @@ public class ProjectPaths {
return path != null ? new File(path) : null;
}
@Nullable
public File getAnnotationProcessorGeneratedSourcesOutputDir(Module module, final boolean forTests, String sourceDirName) {
if (!StringUtil.isEmpty(sourceDirName)) {
List<String> roots = module.getContentRoots();
if (roots.isEmpty()) {
return null;
}
if (roots.size() > 1) {
roots = new ArrayList<String>(roots); // sort roots to get deterministic result
Collections.sort(roots, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
}
return new File(roots.get(0), sourceDirName);
}
final File outputDir = getModuleOutputDir(module, forTests);
if (outputDir == null) {
return null;
}
final File parentFile = outputDir.getParentFile();
if (parentFile == null) {
return null;
}
return new File(parentFile, outputDir.getName() + "_" + DEFAULT_GENERATED_DIR_NAME);
}
public List<String> getProjectRuntimeClasspath(boolean includeTests) {
Set<File> classpath = new LinkedHashSet<File>();
final ClasspathKind kind = ClasspathKind.runtime(includeTests);
@@ -251,18 +251,36 @@ public class IdeaProjectLoader {
def annotationProcessingTag = componentTag?.annotationProcessing
if (annotationProcessingTag != null) {
configuration.annotationProcessing.enabled = parseBoolean(annotationProcessingTag."@enabled", false)
configuration.annotationProcessing.obtainProcessorsFromClasspath = parseBoolean(annotationProcessingTag."@useClasspath", true)
List<String> processorPaths = []
annotationProcessingTag.processorPath?.each {
processorPaths << projectMacroExpander.expandMacros(it."@value")
}
configuration.annotationProcessing.processorsPath = processorPaths.join(File.pathSeparator)
annotationProcessingTag.processor?.each {
configuration.annotationProcessing.processorsOptions[it."@name"] = it."@options" ?: ""
}
annotationProcessingTag.processModule?.each {
configuration.annotationProcessing.processModule[it."@name"] = it."@generatedDirName"
configuration.moduleAnnotationProcessingProfiles = []
annotationProcessingTag?.profile?.each {profileTag ->
AnnotationProcessingProfile profile
if (parseBoolean(profileTag."@default", false)) {
profile = configuration.defaultAnnotationProcessingProfile
}
else {
profile = new AnnotationProcessingProfile()
configuration.moduleAnnotationProcessingProfiles << profile
}
profile.name = profileTag."@name";
profile.enabled = parseBoolean(profileTag."@enabled", false)
profile.generatedSourcesDirName = profileTag.sourceOutputDir?.getAt(0)?."@name"
profileTag.processor?.each {
profile.processors << it."@name"
}
profileTag.option?.each {
profile.processorsOptions[it."@name"] = it."@value" ?: ""
}
def pathTag = profileTag.processorPath?.getAt(0)
profile.obtainProcessorsFromClasspath = parseBoolean(pathTag?."@useClasspath", true)
List<String> processorPaths = []
pathTag?.each {
processorPaths << projectMacroExpander.expandMacros(it."@name")
}
profile.processorsPath = processorPaths.join(File.pathSeparator)
profileTag.module?.each {
profile.processModule << it."@name"
}
}
}
@@ -20,10 +20,16 @@
<entry name="?*.tld" />
<entry name="?*.ftl" />
</wildcardResourcePatterns>
<annotationProcessing enabled="true" useClasspath="false">
<processorPath value="$PROJECT_DIR$/src" />
<processor name="my.proc" options="a=b c=d" />
<processModule name="compilerConfiguration" generatedDirName="gen" />
<annotationProcessing>
<profile default="true" name="Default" enabled="true">
<sourceOutputDir name="gen" />
<option name="a" value="b" />
<option name="c" value="d" />
<processor name="my.proc" />
<processorPath useClasspath="false">
<entry name="$PROJECT_DIR$/src" />
</processorPath>
</profile>
</annotationProcessing>
</component>
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
+10 -4
View File
@@ -20,10 +20,16 @@
<entry name="?*.tld" />
<entry name="?*.ftl" />
</wildcardResourcePatterns>
<annotationProcessing enabled="true" useClasspath="false">
<processorPath value="$PROJECT_DIR$/src" />
<processor name="my.proc" options="a=b c=d" />
<processModule name="compilerConfiguration" generatedDirName="gen" />
<annotationProcessing>
<profile default="true" name="Default" enabled="true">
<sourceOutputDir name="gen" />
<option name="a" value="b" />
<option name="c" value="d" />
<processor name="my.proc" />
<processorPath useClasspath="false">
<entry name="$PROJECT_DIR$/src" />
</processorPath>
</profile>
</annotationProcessing>
</component>
</project>
@@ -33,11 +33,12 @@ class CompilerConfigurationTest extends JpsBuildTestCase {
String basePath = project.modules["compilerConfiguration"].basePath
assertFalse(configuration.clearOutputDirectoryOnRebuild)
assertFalse(configuration.addNotNullAssertions)
assertTrue(configuration.annotationProcessing.enabled)
assertFalse(configuration.annotationProcessing.obtainProcessorsFromClasspath)
assertEquals("$basePath/src", configuration.annotationProcessing.processorsPath)
assertEquals("a=b c=d", configuration.annotationProcessing.processorsOptions["my.proc"])
assertEquals("gen", configuration.annotationProcessing.processModule["compilerConfiguration"])
assertTrue(configuration.defaultAnnotationProcessingProfile.enabled)
assertFalse(configuration.defaultAnnotationProcessingProfile.obtainProcessorsFromClasspath)
assertEquals("$basePath/src", configuration.defaultAnnotationProcessingProfile.processorsPath)
assertEquals("b", configuration.defaultAnnotationProcessingProfile.processorsOptions["a"])
assertEquals("d", configuration.defaultAnnotationProcessingProfile.processorsOptions["c"])
assertEquals("gen", configuration.defaultAnnotationProcessingProfile.generatedSourcesDirName)
assertFalse(configuration.excludes.isExcluded(new File("$basePath/src/nonrec/x/Y.java")))
assertTrue(configuration.excludes.isExcluded(new File("$basePath/src/nonrec/Y.java")))
assertTrue(configuration.excludes.isExcluded(new File("$basePath/src/rec/x/Y.java")))
@@ -8,7 +8,7 @@ java.terms.parameter=parameter
java.terms.variable=variable
java.terms.interface=interface
java.terms.exception=exception
java.terms.static.initializer=static intializer
java.terms.static.initializer=static initializer
java.terms.instance.initializer=instance initializer
java.terms.enum=enum
java.terms.annotation.interface=@interface
@@ -14,7 +14,6 @@ import org.jetbrains.groovy.compiler.rt.GroovyCompilerWrapper;
import org.jetbrains.jps.*;
import org.jetbrains.jps.incremental.*;
import org.jetbrains.jps.incremental.fs.RootDescriptor;
import org.jetbrains.jps.incremental.java.JavaBuilder;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.jetbrains.jps.incremental.messages.FileGeneratedEvent;
import org.jetbrains.jps.incremental.messages.ProgressMessage;
@@ -100,8 +99,7 @@ public class GroovyBuilder extends ModuleLevelBuilder {
if (myForStubs) {
for (Module module : generationOutputs.keySet()) {
File root = new File(generationOutputs.get(module));
context.getRootsIndex().associateRoot(root, module, context.isCompilingTests(), true);
JavaBuilder.addTempSourcePathRoot(context, root);
context.getRootsIndex().associateRoot(root, module, context.isCompilingTests(), true, true);
}
}
@@ -640,7 +640,7 @@ public class Main {
CompileServerManager.instance.shutdownServer()
}
public void "_test make stub-level error and correct it"() {
public void "test make stub-level error and correct it"() {
def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { }')
myFixture.addFileToProject('Bar.java', 'class Bar extends Foo {}')