Merge remote-tracking branch 'origin/master'

This commit is contained in:
Alexander Lobas
2012-05-30 18:33:42 +04:00
65 changed files with 1935 additions and 885 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;
@@ -80,9 +80,11 @@ public class CreateNewLibraryAction extends DumbAwareAction {
@NotNull final Project project, @NotNull final LibrariesModifiableModel modifiableModel) {
final NewLibraryConfiguration configuration = createNewLibraryConfiguration(type, parentComponent, project);
if (configuration == null) return null;
final Library library = modifiableModel.createLibrary(LibraryEditingUtil.suggestNewLibraryName(modifiableModel, configuration.getDefaultLibraryName()), configuration.getLibraryType().getKind());
final LibraryType<?> libraryType = configuration.getLibraryType();
final Library library = modifiableModel.createLibrary(
LibraryEditingUtil.suggestNewLibraryName(modifiableModel, configuration.getDefaultLibraryName()), libraryType != null ? libraryType.getKind() : null);
final NewLibraryEditor editor = new NewLibraryEditor(configuration.getLibraryType(), configuration.getProperties());
final NewLibraryEditor editor = new NewLibraryEditor(libraryType, configuration.getProperties());
configuration.addRoots(editor);
final Library.ModifiableModel model = library.getModifiableModel();
editor.applyTo((LibraryEx.ModifiableModelEx)model);
@@ -540,6 +540,7 @@ public class HighlightUtil {
if (errorResult != null && valueType != null) {
IntentionAction fix = QUICK_FIX_FACTORY.createMethodReturnFix(method, valueType, true);
QuickFixAction.registerQuickFixAction(errorResult, fix);
ChangeParameterClassFix.registerQuickFixAction(returnType, valueType, errorResult);
if (returnType instanceof PsiArrayType && TypeConversionUtil.isAssignable(((PsiArrayType)returnType).getComponentType(), valueType)) {
QuickFixAction.registerQuickFixAction(errorResult, new SurroundWithArrayFix(null) {
@Override
@@ -2507,7 +2508,7 @@ public class HighlightUtil {
QuickFixAction.registerQuickFixAction(highlightInfo, action);
}
}
ChangeParameterClassFix.registerQuickFixAction(parameter, itemType, highlightInfo);
ChangeParameterClassFix.registerQuickFixAction(parameter.getType(), itemType, highlightInfo);
}
@Nullable
@@ -61,11 +61,11 @@ public class ChangeParameterClassFix extends ExtendsListFix {
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
return
super.isAvailable(project, file, startElement, endElement)
&& myClassToExtendFrom != null
&& myClassToExtendFrom.isValid()
&& myClassToExtendFrom.getQualifiedName() != null
;
super.isAvailable(project, file, startElement, endElement)
&& myClassToExtendFrom != null
&& myClassToExtendFrom.isValid()
&& myClassToExtendFrom.getQualifiedName() != null
;
}
@Override
@@ -114,18 +114,21 @@ public class ChangeParameterClassFix extends ExtendsListFix {
UndoUtil.markPsiFileForUndo(file);
}
public static void registerQuickFixAction(PsiVariable variable, PsiType returnType, HighlightInfo info) {
final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(returnType);
final PsiType variableType = variable.getType();
final PsiClass variableClass = PsiUtil.resolveClassInClassTypeOnly(variableType);
if (psiClass != null && variableClass != null && !psiClass.isInheritor(variableClass, true)) {
QuickFixAction.registerQuickFixAction(info, new ChangeParameterClassFix(psiClass, (PsiClassType)variableType));
}
public static void registerQuickFixAction(PsiType lType, PsiType rType, HighlightInfo info) {
final PsiClass lClass = PsiUtil.resolveClassInClassTypeOnly(lType);
final PsiClass rClass = PsiUtil.resolveClassInClassTypeOnly(rType);
if (rClass == null || lClass == null) return;
if (rClass instanceof PsiAnonymousClass) return;
if (rClass.isInheritor(lClass, true)) return;
if (lClass.isInheritor(rClass, true)) return;
QuickFixAction.registerQuickFixAction(info, new ChangeParameterClassFix(rClass, (PsiClassType)lType));
}
public static void registerQuickFixActions(PsiCall methodCall, PsiExpressionList list, HighlightInfo highlightInfo) {
final JavaResolveResult result = methodCall.resolveMethodGenerics();
PsiMethod method = (PsiMethod) result.getElement();
PsiMethod method = (PsiMethod)result.getElement();
final PsiSubstitutor substitutor = result.getSubstitutor();
PsiExpression[] expressions = list.getExpressions();
if (method == null || method.getParameterList().getParametersCount() != expressions.length) return;
@@ -134,12 +137,13 @@ public class ChangeParameterClassFix extends ExtendsListFix {
PsiParameter parameter = method.getParameterList().getParameters()[i];
PsiType expressionType = expression.getType();
PsiType parameterType = substitutor.substitute(parameter.getType());
if (expressionType == null || expressionType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(expressionType) || expressionType instanceof PsiArrayType ) continue;
if (parameterType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(parameterType) || parameterType instanceof PsiArrayType ) continue;
if (expressionType == null || expressionType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(expressionType) || expressionType instanceof PsiArrayType) continue;
if (parameterType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(parameterType) || parameterType instanceof PsiArrayType) continue;
if (parameterType.isAssignableFrom(expressionType)) continue;
PsiClass parameterClass = PsiUtil.resolveClassInType(parameterType);
PsiClass expressionClass = PsiUtil.resolveClassInType(expressionType);
if (parameterClass == null || expressionClass == null) continue;
if (expressionClass instanceof PsiAnonymousClass) continue;
if (parameterClass.isInheritor(expressionClass, true)) continue;
QuickFixAction.registerQuickFixAction(highlightInfo, new ChangeParameterClassFix(expressionClass, (PsiClassType)parameterType));
}
@@ -412,7 +412,7 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
}
}
private void inlineMethodCall(PsiReferenceExpression ref) throws IncorrectOperationException {
public void inlineMethodCall(PsiReferenceExpression ref) throws IncorrectOperationException {
InlineUtil.TailCallType tailCall = InlineUtil.getTailCallType(ref);
ChangeContextUtil.encodeContextInfo(myMethod, false);
myMethodCopy = (PsiMethod)myMethod.copy();
@@ -72,7 +72,7 @@ public class InlineSuperCallUsageInfo extends FixableUsageInfo {
assert inliningClass != null;
methodCopy = (PsiMethod)inliningClass.add(methodCopy);
final InlineMethodProcessor inlineMethodProcessor = new InlineMethodProcessor(getProject(), methodCopy, methodExpression, null, true);
inlineMethodProcessor.run();
inlineMethodProcessor.inlineMethodCall(methodExpression);
methodCopy.delete();
}
}
@@ -30,6 +30,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -356,7 +357,8 @@ public class PushDownProcessor extends BaseRefactoringProcessor {
}
else if (member instanceof PsiMethod) {
PsiMethod method = (PsiMethod)member;
final PsiMethod methodBySignature = targetClass.findMethodBySignature(method, false);
final PsiMethod methodBySignature =
MethodSignatureUtil.findMethodBySuperSignature(targetClass, method.getSignature(substitutor), false);
if (methodBySignature == null) {
final boolean wasInterface = myClass.isInterface();
newMember = (PsiMethod)targetClass.add(method);
@@ -0,0 +1,9 @@
// "Make 'Foo' implement 'Foo.Bar'" "true"
public class Foo implements Foo.Bar {
public Bar getBar() {
return this;
}
public interface Bar {}
}
@@ -0,0 +1,14 @@
// "Make 'null' implement 'Foo.IBar'" "false"
public abstract class Foo {
static Foo anonymous = new Foo() {
@Override
void fooMethod() {
foo2Method(th<caret>is);
}
};
protected Foo() {
IBar bar = anonymou<caret>s;
}
}
@@ -0,0 +1,19 @@
// "Make 'null' implement 'Foo.IBar'" "false"
public abstract class Foo {
public static interface IBar {
void barMethod();
}
abstract void fooMethod();
void foo2Method(IBar b) {
}
static Foo anonymous = new Foo() {
@Override
void fooMethod() {
foo2Method(th<caret>is);
}
};
}
@@ -0,0 +1,10 @@
// "Make 'Foo' implement 'Foo.Bar'" "false"
public class Foo {
public void getBar() {
Bar f = new F<caret>oo();
}
public class Bar extends Foo {
}
}
@@ -0,0 +1,9 @@
// "Make 'Foo' implement 'Foo.Bar'" "true"
public class Foo {
public Bar getBar() {
return t<caret>his;
}
public interface Bar {}
}
@@ -0,0 +1,13 @@
abstract class BaseTask<T, S extends BaseTask<T, S>> {
public abstract S make<caret>Task(int depth, ParallelStream<T> coll);
}
class ForEachTask<T> extends BaseTask<T, ForEachTask<T>> {
public ForEachTask<T> makeTask(int depth, ParallelStream<T> coll) {
return new ForEachTask<T>();
}
}
class ParallelStream<T> {
}
@@ -0,0 +1,12 @@
abstract class BaseTask<T, S extends BaseTask<T, S>> {
}
class ForEachTask<T> extends BaseTask<T, ForEachTask<T>> {
public ForEachTask<T> makeTask(int depth, ParallelStream<T> coll) {
return new ForEachTask<T>();
}
}
class ParallelStream<T> {
}
@@ -115,6 +115,10 @@ public class PushDownTest extends LightRefactoringTestCase {
doTest();
}
public void testOverridingMethodWithSubst() throws Exception {
doTest();
}
public void testSameClassInterface() throws Exception {
final String filePath = "/refactoring/pushDown/" + getTestName(false) + ".java";
configureByFile(filePath);
@@ -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;
@@ -846,7 +846,7 @@ public class Mappings {
}
private class Differential {
static final int DESPERATE_MASK = Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
final int DESPERATE_MASK = Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
final Mappings myDelta;
final Collection<String> myRemoved;
@@ -994,7 +994,7 @@ public class Mappings {
}
}
private void processAddedMethods (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private void processAddedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing added methods: ");
for (final MethodRepr m : diff.methods().added()) {
debug("Method: ", m.name);
@@ -1120,7 +1120,7 @@ public class Mappings {
debug("End of added methods processing");
}
private void processRemovedMethods (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private void processRemovedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing removed methods:");
for (final MethodRepr m : diff.methods().removed()) {
debug("Method ", m.name);
@@ -1216,7 +1216,7 @@ public class Mappings {
debug("End of removed methods processing");
}
private void processChangedMethods (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private void processChangedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing changed methods:");
for (final Pair<MethodRepr, Difference> mr : diff.methods().changed()) {
final MethodRepr m = mr.first;
@@ -1305,7 +1305,7 @@ public class Mappings {
debug("End of changed methods processing");
}
private boolean processAddedFields (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private boolean processAddedFields(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing added fields");
for (final FieldRepr f : diff.fields().added()) {
@@ -1407,7 +1407,7 @@ public class Mappings {
return true;
}
private boolean processRemovedFields (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private boolean processRemovedFields(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing removed fields:");
for (final FieldRepr f : diff.fields().removed()) {
@@ -1434,7 +1434,7 @@ public class Mappings {
return true;
}
private boolean processChangedFields (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private boolean processChangedFields(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing changed fields:");
for (final Pair<FieldRepr, Difference> f : diff.fields().changed()) {
@@ -1623,19 +1623,19 @@ public class Mappings {
debug("End of annotation-specific analysis");
}
processAddedMethods (state, diff, it);
processRemovedMethods (state, diff, it);
processChangedMethods (state, diff, it);
processAddedMethods(state, diff, it);
processRemovedMethods(state, diff, it);
processChangedMethods(state, diff, it);
if (!processAddedFields (state, diff, it)) {
if (!processAddedFields(state, diff, it)) {
return false;
}
if (!processRemovedFields (state, diff, it)) {
if (!processRemovedFields(state, diff, it)) {
return false;
}
if (!processChangedFields (state, diff, it)) {
if (!processChangedFields(state, diff, it)) {
return false;
}
}
@@ -1880,6 +1880,16 @@ public class Mappings {
}
if (delta.myIsDifferentiated) {
final TIntHashSet compiledClasses = new TIntHashSet();
delta.myClassToSourceFile.forEachEntry(new TIntIntProcedure() {
@Override
public boolean execute(final int a, final int b) {
compiledClasses.add(a);
return true;
}
});
for (ClassRepr repr : delta.getDeletedClasses()) {
cleanupRemovedClass(repr, null, subclassesTrashBin, dependenciesTrashBin);
}
@@ -1895,13 +1905,31 @@ public class Mappings {
delta.getChangedClasses().forEach(new TIntProcedure() {
@Override
public boolean execute(int className) {
final TIntHashSet subClasses = delta.myClassToSubclasses.get(className);
if (subClasses != null) {
myClassToSubclasses.replace(className, subClasses);
public boolean execute(final int className) {
TIntHashSet s = delta.myClassToSubclasses.get(className);
final TIntHashSet newSubClasses = s == null ? new TIntHashSet() : s;
final TIntHashSet oldSubClasses = myClassToSubclasses.get(className);
if (oldSubClasses != null) {
oldSubClasses.forEach(new TIntProcedure() {
@Override
public boolean execute(final int value) {
if (!compiledClasses.contains(value)) {
newSubClasses.add(value);
}
return true;
}
}
);
}
if (newSubClasses.size() == 0) {
myClassToSubclasses.remove(className);
}
else {
myClassToSubclasses.remove(className);
myClassToSubclasses.replace(className, newSubClasses);
}
final int sourceFile = delta.myClassToSourceFile.get(className);
@@ -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")))
@@ -204,6 +204,17 @@ public class VfsUtilCore {
}
}
@NotNull
public static String loadText(@NotNull VirtualFile file, int length) throws IOException{
InputStreamReader reader = new InputStreamReader(file.getInputStream(), file.getCharset());
try {
return new String(FileUtil.loadText(reader, length));
}
finally {
reader.close();
}
}
@NotNull
public static VirtualFile[] toVirtualFileArray(@NotNull Collection<? extends VirtualFile> files) {
int size = files.size();
@@ -23,6 +23,8 @@ import com.intellij.openapi.command.undo.DocumentReferenceManager;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.TextRange;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.OutputStream;
@@ -31,7 +33,7 @@ import java.io.OutputStream;
* @author traff
*/
public class ConsoleExecuteActionHandler {
private final ProcessHandler myProcessHandler;
private ProcessHandler myProcessHandler;
private final boolean myPreserveMarkup;
private boolean myAddCurrentToHistory = true;
private ConsoleHistoryModel myConsoleHistoryModel;
@@ -42,6 +44,15 @@ public class ConsoleExecuteActionHandler {
myPreserveMarkup = preserveMarkup;
}
@Nullable
private synchronized ProcessHandler getProcessHandler() {
return myProcessHandler;
}
public synchronized void setProcessHandler(@NotNull final ProcessHandler processHandler) {
myProcessHandler = processHandler;
}
public void setConsoleHistoryModel(ConsoleHistoryModel consoleHistoryModel) {
myConsoleHistoryModel = consoleHistoryModel;
}
@@ -81,7 +92,10 @@ public class ConsoleExecuteActionHandler {
public void sendText(String line) {
//final Charset charset = myProcessHandler.getCharset();
final OutputStream outputStream = myProcessHandler.getProcessInput();
final ProcessHandler handler = getProcessHandler();
assert handler != null : "process handler is null";
final OutputStream outputStream = handler.getProcessInput();
assert outputStream != null : "output stream is null";
try {
//byte[] bytes = (line + "\n").getBytes(charset.name());
byte[] bytes = line.getBytes();
@@ -100,6 +114,11 @@ public class ConsoleExecuteActionHandler {
public void finishExecution() {
}
public final boolean isProcessTerminated() {
final ProcessHandler handler = getProcessHandler();
return handler == null || handler.isProcessTerminated();
}
public String getEmptyExecuteAction() {
return "Console.Execute";
}
@@ -34,7 +34,7 @@ public class ContextHelpAction extends AnAction implements DumbAware {
this(null);
}
public ContextHelpAction(@NonNls String helpID) {
public ContextHelpAction(@NonNls @Nullable String helpID) {
myHelpID = helpID;
}
@@ -63,8 +63,18 @@ public class MultiLevelDiffTool implements DiffTool, DiscloseMultiRequest {
Disposer.dispose(builder);
return;
}
// todo ?
builder.removeAllActions();
final Runnable onOkRunnable = request.getOnOkRunnable();
if (onOkRunnable != null){
builder.setOkOperation(new Runnable() {
@Override
public void run() {
builder.getDialogWrapper().close(0);
onOkRunnable.run();
}
});
} else {
builder.removeAllActions();
}
builder.setCenterPanel(diffPanel.getComponent());
builder.setPreferedFocusComponent(diffPanel.getPreferredFocusedComponent());
builder.setTitle(request.getWindowTitle());
@@ -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
@@ -238,7 +238,7 @@ public class ChangesFragmentedDiffPanel implements Disposable {
final DialogWrapper wrapper = ((DialogWrapperDialog)window).getDialogWrapper();
if (wrapper != null) {
Disposer.dispose(wrapper.getDisposable());
wrapper.close(0);
wrapper.close(DialogWrapper.CANCEL_EXIT_CODE);
ApplicationManager.getApplication().invokeLater(runnable, ModalityState.NON_MODAL, myProject.getDisposed());
return;
}
@@ -221,7 +221,7 @@ public class ApplyPatchAction extends DumbAwareAction {
simpleRequest.setContents(new SimpleContent(texts.getLocal().toString(), file.getFileType()),
mergedDocument);
simpleRequest.setContentTitles(VcsBundle.message("diff.title.local"), "Patched (with problems)");
simpleRequest.addHint(DiffTool.HINT_SHOW_NOT_MODAL_DIALOG);
simpleRequest.addHint(DiffTool.HINT_SHOW_MODAL_DIALOG);
simpleRequest.addHint(DiffTool.HINT_DIFF_IS_APPROXIMATE);
if (! readonly) {
@@ -6,7 +6,7 @@
</extensions>
<extensions defaultExtensionNs="com.intellij">
<compiler implementation="org.jetbrains.android.compiler.AndroidExternalApklibExtractingCompiler" order="first"/>
<compiler implementation="org.jetbrains.android.compiler.AndroidMavenResourcesCompiler"/>
<compiler implementation="org.jetbrains.android.compiler.AndroidMavenResourcesCompiler" order="first"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains">
<android.mavenProvider implementation="org.jetbrains.android.maven.AndroidMavenProviderImpl"/>
@@ -7,13 +7,13 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.android.dom.manifest.Manifest;
import com.intellij.util.xml.NanoXmlUtil;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -55,13 +55,16 @@ public class AndroidBuildConfigGeneratingCompiler implements SourceGeneratingCom
continue;
}
final Manifest manifest = AndroidUtils.loadDomElement(module, manifestFile, Manifest.class);
if (manifest == null) {
context.addMessage(CompilerMessageCategory.ERROR, "Cannot parse file", manifestFile.getUrl(), -1, -1);
String packageName;
try {
// we cannot use DOM here because custom manifest file can be excluded (ex. it can be located in /target/ folder)
packageName = parsePackageName(manifestFile);
}
catch (IOException e) {
context.addMessage(CompilerMessageCategory.ERROR, "I/O error: " + e.getMessage(), null, -1, -1);
continue;
}
String packageName = manifest.getPackage().getValue();
if (packageName != null) {
packageName = packageName.trim();
}
@@ -113,6 +116,31 @@ public class AndroidBuildConfigGeneratingCompiler implements SourceGeneratingCom
return result.toArray(new GenerationItem[result.size()]);
}
@Nullable
private static String parsePackageName(@NotNull VirtualFile manifestFile) throws IOException {
final Ref<String> packageNameRef = Ref.create(null);
NanoXmlUtil.parse(manifestFile.getInputStream(), new NanoXmlUtil.BaseXmlBuilder() {
@Override
public void addAttribute(String key, String nsPrefix, String nsURI, String value, String type)
throws Exception {
super.addAttribute(key, nsPrefix, nsURI, value, type);
if ("package".equals(key) && NanoXmlUtil.createLocation("manifest").equals(getLocation())) {
packageNameRef.set(value);
stop();
}
}
@Override
public void elementAttributesProcessed(String name, String nsPrefix, String nsURI) throws Exception {
super.elementAttributesProcessed(name, nsPrefix, nsURI);
stop();
}
});
return packageNameRef.get();
}
@NotNull
@Override
public String getDescription() {
@@ -129,7 +157,7 @@ public class AndroidBuildConfigGeneratingCompiler implements SourceGeneratingCom
return new MyValidityState(in);
}
private static class MyGenerationItem implements GenerationItem{
private static class MyGenerationItem implements GenerationItem {
final Module myModule;
final String myPackage;
final boolean myDebug;
@@ -190,4 +218,4 @@ public class AndroidBuildConfigGeneratingCompiler implements SourceGeneratingCom
out.writeBoolean(myDebug);
}
}
}
}
@@ -71,6 +71,7 @@ public class AndroidRootUtil {
return getFileByRelativeModulePath(facet.getModule(), facet.getConfiguration().CUSTOM_COMPILER_MANIFEST, false);
}
// DO NOT get PSI or DOM from this file, because it may be excluded (f.ex. it can be in /target/ directory)
@Nullable
public static VirtualFile getManifestFileForCompiler(@NotNull AndroidFacet facet) {
return facet.getConfiguration().USE_CUSTOM_COMPILER_MANIFEST
@@ -16,6 +16,7 @@
package org.jetbrains.idea.devkit.dom.impl;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.Iconable;
import com.intellij.util.xml.DomFileDescription;
import org.jetbrains.idea.devkit.dom.IdeaPlugin;
@@ -33,7 +34,7 @@ public class PluginXmlDomFileDescription extends DomFileDescription<IdeaPlugin>
}
@Override
public Icon getFileIcon(int flags) {
public Icon getFileIcon(@Iconable.IconFlags int flags) {
return ICON;
}
}
@@ -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);
}
}
@@ -60,8 +60,10 @@ import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.annotator.intentions.*;
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicMethodFix;
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicPropertyFix;
import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
import org.jetbrains.plugins.groovy.debugger.fragments.GroovyCodeFragment;
import org.jetbrains.plugins.groovy.dsl.toplevel.AnnotatedContextFilter;
import org.jetbrains.plugins.groovy.extensions.GroovyUnresolvedHighlightFilter;
import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter;
import org.jetbrains.plugins.groovy.lang.documentation.GroovyPresentationUtil;
@@ -101,12 +103,14 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatem
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.types.*;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrVariableDeclarationOwner;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.TypeInferenceHelper;
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -128,6 +132,9 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
if (element instanceof GroovyPsiElement) {
myHolder = holder;
((GroovyPsiElement)element).accept(this);
if (isCompileStatic(element)) {
GroovyAssignabilityCheckInspection.checkElement((GroovyPsiElement)element, holder);
}
myHolder = null;
}
else {
@@ -324,6 +331,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
PsiElement resolved = resolveResult.getElement();
final PsiElement parent = referenceExpression.getParent();
if (resolved != null) {
if (resolved instanceof PsiMember) {
highlightMemberResolved(myHolder, referenceExpression, ((PsiMember)resolved));
@@ -337,7 +345,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
Annotation annotation = myHolder.createInfoAnnotation(referenceExpression,
GroovyBundle.message("cannot.reference.nonstatic",
referenceExpression.getReferenceName()));
annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS);
annotation.setTextAttributes(isStaticallyCompiled(referenceExpression)?DefaultHighlighter.BAD_CHARACTER:DefaultHighlighter.UNRESOLVED_ACCESS);
}
}
}
@@ -377,8 +385,22 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
PsiElement refNameElement = referenceExpression.getReferenceNameElement();
PsiElement elt = refNameElement == null ? referenceExpression : refNameElement;
Annotation annotation = myHolder.createInfoAnnotation(elt, null);
final GrExpression qualifier = referenceExpression.getQualifierExpression();
Annotation annotation;
boolean compileStatic = isCompileStatic(referenceExpression);
if (compileStatic) {
annotation = myHolder.createInfoAnnotation(elt, GroovyBundle.message("cannot.resolve", referenceExpression.getReferenceName()));
annotation.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
}
else {
if (qualifier != null && qualifier.getType() == null) return;
annotation = myHolder.createInfoAnnotation(elt, null);
annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS);
}
if (qualifier == null) {
if (parent instanceof GrMethodCall) {
registerStaticImportFix(referenceExpression, annotation);
@@ -388,20 +410,22 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
registerAddImportFixes(referenceExpression, annotation);
}
}
else {
if (qualifier.getType() == null) {
return;
}
}
registerReferenceFixes(referenceExpression, annotation);
registerReferenceFixes(referenceExpression, annotation, compileStatic);
UnresolvedReferenceQuickFixProvider.registerReferenceFixes(referenceExpression, new QuickFixActionRegistrarAdapter(annotation));
OrderEntryFix.registerFixes(new QuickFixActionRegistrarAdapter(annotation), referenceExpression);
annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS);
}
}
private static boolean isCompileStatic(PsiElement e) {
PsiMember containingMember = PsiTreeUtil.getParentOfType(e, PsiMember.class);
return containingMember != null && GroovyPsiManager.getInstance(containingMember.getProject()).isCompileStatic(containingMember);
}
private static boolean isStaticallyCompiled(GrReferenceExpression referenceExpression) {
return AnnotatedContextFilter.findContextAnnotation(referenceExpression, GroovyCommonClassNames.GROOVY_TRANSFORM_COMPILE_STATIC)!=null;
}
private void highlightVariable(GrVariable variable, PsiElement toHighlight) {
Annotation annotation = myHolder.createInfoAnnotation(toHighlight, null);
boolean reassigned = isReassigned(variable);
@@ -1772,11 +1796,13 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
}
private static void registerReferenceFixes(GrReferenceExpression refExpr, Annotation annotation) {
PsiClass targetClass = QuickfixUtil.findTargetClass(refExpr);
private static void registerReferenceFixes(GrReferenceExpression refExpr, Annotation annotation, boolean compileStatic) {
PsiClass targetClass = QuickfixUtil.findTargetClass(refExpr, compileStatic);
if (targetClass == null) return;
addDynamicAnnotation(annotation, refExpr);
if (!compileStatic) {
addDynamicAnnotation(annotation, refExpr);
}
if (targetClass.isWritable()) {
if (!(targetClass instanceof GroovyScriptClass)) {
if (targetClass instanceof GrMemberOwner) {
@@ -26,7 +26,6 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.SuggestedNameInfo;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.util.ArrayUtil;
import gnu.trove.THashSet;
@@ -34,13 +33,13 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ParamInfo;
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicElementSettings;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceResolveUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -53,22 +52,13 @@ import java.util.*;
*/
public class QuickfixUtil {
@Nullable
public static PsiClass findTargetClass(GrReferenceExpression refExpr) {
final PsiClass psiClass;
if (refExpr.isQualified()) {
GrExpression qualifier = refExpr.getQualifierExpression();
PsiType type = qualifier.getType();
if (!(type instanceof PsiClassType)) return null;
psiClass = ((PsiClassType)type).resolve();
} else {
GroovyPsiElement context = PsiTreeUtil.getParentOfType(refExpr, GrTypeDefinition.class, GroovyFileBase.class);
if (context instanceof GrTypeDefinition) {
return (PsiClass)context;
} else if (context instanceof GroovyFileBase) return ((GroovyFileBase)context).getScriptClass();
return null;
public static PsiClass findTargetClass(GrReferenceExpression refExpr, boolean compileStatic) {
PsiType type = GrReferenceResolveUtil.getQualifierType(refExpr);
if (type == null && compileStatic) {
return GroovyPsiManager.getInstance(refExpr.getProject()).findClassWithCache(CommonClassNames.JAVA_LANG_OBJECT, refExpr.getResolveScope());
}
return psiClass;
if (!(type instanceof PsiClassType)) return null;
return ((PsiClassType)type).resolve();
}
public static boolean isStaticCall(GrReferenceExpression refExpr) {
@@ -184,7 +174,7 @@ public class QuickfixUtil {
public static DynamicElementSettings createSettings(GrReferenceExpression referenceExpression) {
DynamicElementSettings settings = new DynamicElementSettings();
final PsiClass containingClass = findTargetClass(referenceExpression);
final PsiClass containingClass = findTargetClass(referenceExpression, false);
assert containingClass != null;
String className = containingClass.getQualifiedName();
@@ -16,14 +16,22 @@
package org.jetbrains.plugins.groovy.codeInspection.assignment;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -31,7 +39,6 @@ import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.annotator.GroovyAnnotator;
import org.jetbrains.plugins.groovy.codeInspection.BaseInspection;
import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor;
import org.jetbrains.plugins.groovy.codeInspection.GroovyFix;
import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
@@ -45,6 +52,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
@@ -56,10 +64,12 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrString;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceResolveUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
@@ -80,11 +90,6 @@ import java.util.Map;
public class GroovyAssignabilityCheckInspection extends BaseInspection {
private static final Logger LOG = Logger.getInstance(GroovyAssignabilityCheckInspection.class);
@Override
protected GroovyFix buildFix(PsiElement location) {
return super.buildFix(location); //To change body of overridden methods use File | Settings | File Templates.
}
@Nls
@NotNull
@Override
@@ -159,6 +164,8 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
@Override
public void visitMethod(GrMethod method) {
if (GroovyPsiManager.getInstance(method.getProject()).isCompileStatic(method)) return;
super.visitMethod(method);
final GrOpenBlock block = method.getBlock();
if (block == null) return;
@@ -178,6 +185,18 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
});
}
@Override
public void visitField(GrField field) {
if (GroovyPsiManager.getInstance(field.getProject()).isCompileStatic(field)) return;
super.visitField(field);
}
@Override
public void visitTypeDefinition(GrTypeDefinition typeDefinition) {
if (GroovyPsiManager.getInstance(typeDefinition.getProject()).isCompileStatic(typeDefinition)) return;
super.visitTypeDefinition(typeDefinition);
}
@Override
public void visitReturnStatement(GrReturnStatement returnStatement) {
super.visitReturnStatement(returnStatement);
@@ -761,4 +780,75 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
}
return GrReferenceResolveUtil.getQualifierType(place);
}
private static class AnnotatingVisitor extends MyVisitor {
private AnnotationHolder myHolder;
@Override
protected void registerError(@NotNull final PsiElement location,
final String description,
final LocalQuickFix[] fixes,
final ProblemHighlightType highlightType) {
Annotation annotation = myHolder.createErrorAnnotation(location, description);
for (final LocalQuickFix fix : fixes) {
annotation.registerFix(new IntentionAction() {
@NotNull
@Override
public String getText() {
return fix.getName();
}
@NotNull
@Override
public String getFamilyName() {
return fix.getFamilyName();
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return true;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
InspectionManager manager = InspectionManager.getInstance(project);
ProblemDescriptor descriptor = manager.createProblemDescriptor(location, description, fixes, highlightType, fixes.length == 1, false);
fix.applyFix(project, descriptor);
}
@Override
public boolean startInWriteAction() {
return true;
}
});
}
}
@Override
public void visitElement(GroovyPsiElement element) {
//do nothing
}
}
private static final ThreadLocal<AnnotatingVisitor> visitor = new ThreadLocal<AnnotatingVisitor>() {
@Override
protected AnnotatingVisitor initialValue() {
return new AnnotatingVisitor();
}
};
public static void checkElement(GroovyPsiElement e, AnnotationHolder holder) {
AnnotatingVisitor annotatingVisitor = visitor.get();
AnnotationHolder oldHolder = annotatingVisitor.myHolder;
try {
annotatingVisitor.myHolder = holder;
e.accept(annotatingVisitor);
}
finally {
annotatingVisitor.myHolder = oldHolder;
}
}
}
@@ -77,15 +77,9 @@ public class GroovyBraceEnforcer extends GroovyRecursiveElementVisitor {
// if (true) i = 1; // Cool assignment
// We can't just surround target block of code with curly braces because the closing one will be treated as comment as well.
// Hence, we perform a check if we have such situation at the moment and insert new line before the closing brace.
int lastLineFeedIndex = oldText.lastIndexOf("\n");
lastLineFeedIndex = Math.max(0, lastLineFeedIndex);
int lastLineCommentIndex = oldText.indexOf("//", lastLineFeedIndex);
StringBuilder buf = new StringBuilder(oldText.length() + 5);
buf.append("{ ").append(oldText);
if (lastLineCommentIndex >= 0) {
buf.append("\n");
}
buf.append(" }");
buf.append("{\n").append(oldText);
buf.append("\n}");
final int oldTextLength = statement.getTextLength();
try {
CodeEditUtil.replaceChild(SourceTreeToPsiMap.psiElementToTree(statement),
@@ -65,6 +65,7 @@ public class GroovyPsiManager {
private final ConcurrentMap<GroovyPsiElement, PsiType> myCalculatedTypes = new ConcurrentWeakHashMap<GroovyPsiElement, PsiType>();
private final ConcurrentMap<String, SoftReference<Map<GlobalSearchScope, PsiClass>>> myClassCache = new ConcurrentHashMap<String, SoftReference<Map<GlobalSearchScope, PsiClass>>>();
private final ConcurrentMap<PsiMember, Boolean> myCompileStatic = new ConcurrentHashMap<PsiMember, Boolean>();
private static final RecursionGuard ourGuard = RecursionManager.createGuard("groovyPsiManager");
@@ -92,6 +93,7 @@ public class GroovyPsiManager {
public void dropTypesCache() {
myCalculatedTypes.clear();
myCompileStatic.clear();
}
public static boolean isInheritorCached(@Nullable PsiClass aClass, @NotNull String baseClassName) {
@@ -122,6 +124,25 @@ public class GroovyPsiManager {
return JavaPsiFacade.getElementFactory(myProject).createTypeByFQClassName(fqName, resolveScope);
}
public boolean isCompileStatic(PsiMember member) {
Boolean aBoolean = myCompileStatic.get(member);
if (aBoolean == null) {
aBoolean = ConcurrencyUtil.cacheOrGet(myCompileStatic, member, isCompileStaticInner(member));
}
return aBoolean;
}
private boolean isCompileStaticInner(PsiMember member) {
PsiModifierList list = member.getModifierList();
if (list != null) {
PsiAnnotation annotation = list.findAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_COMPILE_STATIC);
if (annotation != null) return true;
}
PsiClass aClass = member.getContainingClass();
if (aClass != null) return isCompileStatic(aClass);
return false;
}
@Nullable
public PsiClass findClassWithCache(String fqName, GlobalSearchScope resolveScope) {
SoftReference<Map<GlobalSearchScope, PsiClass>> reference = myClassCache.get(fqName);
@@ -50,7 +50,8 @@ public final class GroovyCommonClassNames {
@NonNls public static final String GROOVY_LANG_USE = "groovy.lang.Use";
@NonNls public static final String GROOVY_LANG_MIXIN = "groovy.lang.Mixin";
@NonNls public static final String GROOVY_UTIL_TEST_CASE = "groovy.util.GroovyTestCase";
public static final String GROOVY_LANG_SINGLETON = "groovy.lang.Singleton";
@NonNls public static final String GROOVY_LANG_SINGLETON = "groovy.lang.Singleton";
@NonNls public static final String GROOVY_TRANSFORM_COMPILE_STATIC = "groovy.transform.CompileStatic";
private GroovyCommonClassNames() {
@@ -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 {}')
@@ -1009,4 +1009,53 @@ use(Ca) {
''', GroovyAssignabilityCheckInspection)
}
void testCompileStatic() {
myFixture.addClass('''\
package groovy.transform;
public @interface CompileStatic {
}''')
myFixture.configureByText('_.groovy', '''\
<info descr="null">import</info> <info descr="null">groovy.transform.CompileStatic</info>
<info descr="null">class</info> <info descr="null">A</info> {
<info descr="null">def</info> <info descr="null">foo</info>() {
<info descr="null">print</info> <info descr="null">abc</info>
}
<info descr="null">@CompileStatic</info>
<info descr="null">def</info> <info descr="null">bar</info>() {
<info descr="null">print</info> <info descr="Cannot resolve symbol 'abc'">abc</info>
}
}
''')
myFixture.testHighlighting(true, true, true)
}
void testCompileStaticWithAssignabilityCheck() {
myFixture.addClass('''\
package groovy.transform;
public @interface CompileStatic {
}''')
myFixture.configureByText('_.groovy', '''\
import groovy.transform.CompileStatic
class A {
def foo(String s) {
int x = <warning descr="Cannot assign 'Date' to 'int'">new Date()</warning>
}
@CompileStatic
def bar() {
int x = <error descr="Cannot assign 'Date' to 'int'">new Date()</error>
}
}
''')
myFixture.enableInspections(GroovyAssignabilityCheckInspection)
myFixture.checkHighlighting(true, false, true)
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.idea.svn;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vfs.LocalFileSystem;
@@ -50,7 +51,7 @@ public class SvnRecursiveStatusWalker {
}
public void go(final FilePath rootPath, final SVNDepth depth) throws SVNException {
final MyItem root = new MyItem(myProject, rootPath, depth, myPartner.createStatusClient(), true);
final MyItem root = new MyItem(myProject, rootPath, depth, myPartner.createStatusClient(), false);
myQueue.add(root);
while (! myQueue.isEmpty()) {
@@ -177,7 +178,7 @@ public class SvnRecursiveStatusWalker {
}
public void checkIfCopyRootWasReported() {
if (! myMetCurrentItem && myCurrentItem.isIsInnerCopyRoot()) {
if (! myMetCurrentItem) {
myMetCurrentItem = true;
final SVNStatus statusInner = SvnUtil.getStatus(SvnVcs.getInstance(myProject), myCurrentItem.getPath().getIOFile());
if (statusInner == null) return;
@@ -200,7 +201,7 @@ public class SvnRecursiveStatusWalker {
if (SVNStatusType.OBSTRUCTED.equals(status) || SVNStatusType.STATUS_NONE.equals(status)) {
return;
}
if (vf != null) {
if (vf != null && myCurrentItem.isIsInnerCopyRoot()) {
myReceiver.processCopyRoot(vf, statusInner.getURL(),
WorkingCopyFormat.getInstance(statusInner.getWorkingCopyFormat()));
}
@@ -217,7 +218,7 @@ public class SvnRecursiveStatusWalker {
if ((vFile != null) && (SvnVcs.svnStatusIsUnversioned(status))) {
if (vFile.isDirectory()) {
if (myCurrentItem.getPath().getIOFile().equals(ioFile)) {
if (FileUtil.filesEqual(myCurrentItem.getPath().getIOFile(), ioFile)) {
myReceiver.processUnversioned(vFile);
processRecursively(vFile, myCurrentItem.getDepth());
} else {
@@ -18,6 +18,7 @@ package org.jetbrains.idea.svn.commandLine;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.Consumer;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.portable.SvnExceptionWrapper;
@@ -32,6 +33,7 @@ import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringBufferInputStream;
@@ -106,9 +108,8 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient {
try {
final String result = command.run();
// todo not synchronized wrapper stream!
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(new StringBufferInputStream(result), infoHandler[0]);
parser.parse(new ByteArrayInputStream(result.getBytes(CharsetToolkit.UTF8_CHARSET)), infoHandler[0]);
}
catch (SvnExceptionWrapper e) {
@@ -18,6 +18,7 @@ package org.jetbrains.idea.svn.commandLine;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.containers.Convertor;
import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.portable.PortableStatus;
@@ -156,9 +157,8 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI {
try {
final String result = command.run();
// todo not synchronized wrapper stream!
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(new StringBufferInputStream(result), svnHandl[0]);
parser.parse(new ByteArrayInputStream(result.getBytes(CharsetToolkit.UTF8_CHARSET)), svnHandl[0]);
if (! svnHandl[0].isAnythingReported()) {
if (! SvnUtil.isSvnVersioned(myProject, path)) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY));
@@ -18,6 +18,7 @@ package com.intellij.util.xml;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.Iconable;
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
@@ -151,7 +152,7 @@ public class DomFileDescription<T> {
}
@Nullable
public Icon getFileIcon(int flags) {
public Icon getFileIcon(@Iconable.IconFlags int flags) {
return null;
}