diff --git a/community-resources/src/idea_community_about.png b/community-resources/src/idea_community_about.png index 2b5a763fd9c5..d5e5a353e8ef 100644 Binary files a/community-resources/src/idea_community_about.png and b/community-resources/src/idea_community_about.png differ diff --git a/community-resources/src/idea_community_about@2x.png b/community-resources/src/idea_community_about@2x.png index f159fb0a2e56..72bc8c68a9d5 100644 Binary files a/community-resources/src/idea_community_about@2x.png and b/community-resources/src/idea_community_about@2x.png differ diff --git a/community-resources/src/idea_community_logo.png b/community-resources/src/idea_community_logo.png index 91a8153fe2dc..4465f9545620 100644 Binary files a/community-resources/src/idea_community_logo.png and b/community-resources/src/idea_community_logo.png differ diff --git a/community-resources/src/idea_community_logo@2x.png b/community-resources/src/idea_community_logo@2x.png index 1f2cfb1dcceb..dc9a5a0af2de 100644 Binary files a/community-resources/src/idea_community_logo@2x.png and b/community-resources/src/idea_community_logo@2x.png differ diff --git a/platform/lang-api/src/com/intellij/execution/configurations/CompatibilityAwareRunProfile.java b/platform/lang-api/src/com/intellij/execution/configurations/CompatibilityAwareRunProfile.java new file mode 100644 index 000000000000..abea299bdb30 --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/configurations/CompatibilityAwareRunProfile.java @@ -0,0 +1,14 @@ +package com.intellij.execution.configurations; + +import org.jetbrains.annotations.NotNull; + +public interface CompatibilityAwareRunProfile { + /** + * Checks whether the run configuration is compatible with the configuration passed as a parameter + * and may still run if the configuration passed as a parameter starts as well. + * + * @param configuration the run configuration to check a compatibility to run with the current configuration. + * @return true if the configuration can still run along side with the configuration passed as parameter, false otherwise. + */ + boolean isCompatibleWith(@NotNull RunConfiguration configuration); +} diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java index 455e41b585d5..fe101fdcd940 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java @@ -38,7 +38,8 @@ import java.util.List; * * @author dyoma */ -public abstract class RunConfigurationBase extends UserDataHolderBase implements RunConfiguration, TargetAwareRunProfile { +public abstract class RunConfigurationBase extends UserDataHolderBase + implements RunConfiguration, TargetAwareRunProfile, CompatibilityAwareRunProfile { private final ConfigurationFactory myFactory; private final Project myProject; private String myName = ""; @@ -119,6 +120,11 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements return true; } + @Override + public boolean isCompatibleWith(@NotNull RunConfiguration configuration) { + return true; + } + public final boolean equals(final Object obj) { return super.equals(obj); } diff --git a/platform/lang-impl/src/com/intellij/execution/RunManagerConfig.java b/platform/lang-impl/src/com/intellij/execution/RunManagerConfig.java index 71049b4ee7d7..9277b7b36e22 100644 --- a/platform/lang-impl/src/com/intellij/execution/RunManagerConfig.java +++ b/platform/lang-impl/src/com/intellij/execution/RunManagerConfig.java @@ -28,6 +28,7 @@ public class RunManagerConfig { public static final int MIN_RECENT_LIMIT = 0; @NonNls private static final String RECENTS_LIMIT = "recentsLimit"; @NonNls private static final String RESTART_REQUIRES_CONFIRMATION = "restartRequiresConfirmation"; + @NonNls private static final String STOP_INCOMPATIBLE_REQUIRES_CONFIRMATION = "stopIncompatibleRequiresConfirmation"; public RunManagerConfig(PropertiesComponent propertiesComponent, RunManagerImpl manager) { @@ -52,7 +53,15 @@ public class RunManagerConfig { return myPropertiesComponent.getBoolean(RESTART_REQUIRES_CONFIRMATION, true); } - public void setRestartRequiresConfirmation (boolean restartRequiresConfirmation) { + public void setRestartRequiresConfirmation(boolean restartRequiresConfirmation) { myPropertiesComponent.setValue(RESTART_REQUIRES_CONFIRMATION, String.valueOf(restartRequiresConfirmation)); } + + public boolean isStopIncompatibleRequiresConfirmation() { + return myPropertiesComponent.getBoolean(STOP_INCOMPATIBLE_REQUIRES_CONFIRMATION, true); + } + + public void setStopIncompatibleRequiresConfirmation(boolean stopIncompatibleRequiresConfirmation) { + myPropertiesComponent.setValue(STOP_INCOMPATIBLE_REQUIRES_CONFIRMATION, String.valueOf(stopIncompatibleRequiresConfirmation)); + } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java index d984ad2bc583..40c840652c16 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java @@ -45,6 +45,8 @@ import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.ui.docking.DockManager; import com.intellij.util.Alarm; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Predicate; +import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -143,8 +145,9 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom @Override public void run() { for (BeforeRunTask task : activeTasks) { - if (myProject.isDisposed()) + if (myProject.isDisposed()) { return; + } BeforeRunTaskProvider provider = BeforeRunTaskProvider.getProvider(myProject, task.getProviderId()); if (provider == null) { LOG.warn("Cannot find BeforeRunTaskProvider for id='" + task.getProviderId() + "'"); @@ -313,26 +316,43 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom RunnerRegistry.getInstance().getRunner(executor.getId(), configuration != null && configuration.getConfiguration() != null ? configuration.getConfiguration() - : runProfile); + : runProfile + ); if (configuration != null && runner == null) { LOG.error("Cannot find runner for " + configuration.getName()); return; } - final List descriptorsToStop = new ArrayList(); + final List runningConfigurationsOfTheSameType = new ArrayList(); + final List runningIncompatibleConfigurations = new ArrayList(); + + if (configuration != null) { + runningIncompatibleConfigurations.addAll(getIncompatibleRunningDescriptors(configuration)); + } if (configuration != null && configuration.isSingleton()) { - descriptorsToStop.addAll(getRunningDescriptors(configuration)); + runningConfigurationsOfTheSameType.addAll(getRunningDescriptorsOfTheSameConfigType(configuration)); } else if (currentDescriptor != null) { - descriptorsToStop.add(currentDescriptor); + runningConfigurationsOfTheSameType.add(currentDescriptor); } - if (!descriptorsToStop.isEmpty()) { - if (configuration != null && (descriptorsToStop.size() > 1 || currentDescriptor == null || descriptorsToStop.get(0) != currentDescriptor) && - !userApprovesStop(project, configuration.getName(), descriptorsToStop.size())) { - return; + final List runningConfigurationsToStop = ContainerUtil.concat(runningConfigurationsOfTheSameType, + runningIncompatibleConfigurations); + if (!runningConfigurationsToStop.isEmpty()) { + if (configuration != null) { + if (!runningConfigurationsOfTheSameType.isEmpty() + && (runningConfigurationsOfTheSameType.size() > 1 || + currentDescriptor == null || + runningConfigurationsOfTheSameType.get(0) != currentDescriptor) && + !userApprovesStopForSameTypeConfigurations(project, configuration.getName(), runningConfigurationsOfTheSameType.size())) { + return; + } + if (!runningIncompatibleConfigurations.isEmpty() + && !userApprovesStopForIncompatibleConfigurations(myProject, configuration.getName(), runningIncompatibleConfigurations)) { + return; + } } - for (RunContentDescriptor descriptor : descriptorsToStop) { + for (RunContentDescriptor descriptor : runningConfigurationsToStop) { stop(descriptor); } } @@ -344,14 +364,15 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom awaitingTerminationAlarm.addRequest(this, 100); return; } - for (RunContentDescriptor descriptor : descriptorsToStop) { + for (RunContentDescriptor descriptor : runningConfigurationsOfTheSameType) { ProcessHandler processHandler = descriptor.getProcessHandler(); if (processHandler != null && !processHandler.isProcessTerminated()) { awaitingTerminationAlarm.addRequest(this, 100); return; } } - start(project, context, runner, runProfile, runnerSettings, configurationPerRunnerSettings, configuration, executor, target, currentDescriptor); + start(project, context, runner, runProfile, runnerSettings, configurationPerRunnerSettings, configuration, executor, target, + currentDescriptor); } }; awaitingTerminationAlarm.addRequest(runnable, 50); @@ -380,7 +401,7 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom } } - private static boolean userApprovesStop(Project project, String configName, int instancesCount) { + private static boolean userApprovesStopForSameTypeConfigurations(Project project, String configName, int instancesCount) { RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(project); final RunManagerConfig config = runManager.getConfig(); if (!config.isRestartRequiresConfirmation()) return true; @@ -420,10 +441,90 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom Messages.getQuestionIcon(), option) == Messages.OK; } - private List getRunningDescriptors(RunnerAndConfigurationSettings configuration) { + private static boolean userApprovesStopForIncompatibleConfigurations(Project project, + String configName, + List runningIncompatibleDescriptors) { + RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(project); + final RunManagerConfig config = runManager.getConfig(); + if (!config.isStopIncompatibleRequiresConfirmation()) return true; + + DialogWrapper.DoNotAskOption option = new DialogWrapper.DoNotAskOption() { + @Override + public boolean isToBeShown() { + return config.isStopIncompatibleRequiresConfirmation(); + } + + @Override + public void setToBeShown(boolean value, int exitCode) { + config.setStopIncompatibleRequiresConfirmation(value); + } + + @Override + public boolean canBeHidden() { + return true; + } + + @Override + public boolean shouldSaveOptionsOnCancel() { + return false; + } + + @Override + public String getDoNotShowMessage() { + return CommonBundle.message("dialog.options.do.not.show"); + } + }; + + final StringBuilder names = new StringBuilder(); + for (final RunContentDescriptor descriptor : runningIncompatibleDescriptors) { + String name = descriptor.getDisplayName(); + if (names.length() > 0) { + names.append(", "); + } + names.append(name.equals(null) || name.isEmpty() ? ExecutionBundle.message("run.configuration.no.name") + : String.format("'%s'", name)); + } + + //noinspection DialogTitleCapitalization + return Messages.showOkCancelDialog( + project, + ExecutionBundle.message("stop.incompatible.confirmation.message", + configName, names.toString(), runningIncompatibleDescriptors.size()), + ExecutionBundle.message("incompatible.configuration.is.running.dialog.title", runningIncompatibleDescriptors.size()), + ExecutionBundle.message("stop.incompatible.confirmation.button.text"), + CommonBundle.message("button.cancel"), + Messages.getQuestionIcon(), option) == Messages.OK; + } + + private List getRunningDescriptorsOfTheSameConfigType( + @NotNull final RunnerAndConfigurationSettings configurationAndSettings) { + return getRunningDescriptors(new Predicate() { + @Override + public boolean apply(@Nullable RunnerAndConfigurationSettings runningConfigurationAndSettings) { + return configurationAndSettings == runningConfigurationAndSettings; + } + }); + } + + private List getIncompatibleRunningDescriptors( + @NotNull final RunnerAndConfigurationSettings configurationAndSettings) { + final RunConfiguration configurationToCheckCompatibility = configurationAndSettings.getConfiguration(); + return getRunningDescriptors(new Predicate() { + @Override + public boolean apply(@Nullable RunnerAndConfigurationSettings runningConfigurationAndSettings) { + if (runningConfigurationAndSettings == null) return false; + RunConfiguration runningConfiguration = runningConfigurationAndSettings.getConfiguration(); + if (runningConfiguration == null || !(runningConfiguration instanceof CompatibilityAwareRunProfile)) return false; + return !((CompatibilityAwareRunProfile)runningConfiguration).isCompatibleWith(configurationToCheckCompatibility); + } + }); + } + + private List getRunningDescriptors( + Predicate condition) { List result = new ArrayList(); for (Trinity trinity : myRunningConfigurations) { - if (trinity.getSecond() == configuration) { + if (condition.apply(trinity.getSecond())) { ProcessHandler processHandler = trinity.getFirst().getProcessHandler(); if (processHandler != null && !processHandler.isProcessTerminating() && !processHandler.isProcessTerminated()) { result.add(trinity.getFirst()); @@ -433,7 +534,6 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom return result; } - private static void stop(RunContentDescriptor runContentDescriptor) { ProcessHandler processHandler = runContentDescriptor != null ? runContentDescriptor.getProcessHandler() : null; if (processHandler == null) { diff --git a/platform/platform-resources-en/src/messages/ExecutionBundle.properties b/platform/platform-resources-en/src/messages/ExecutionBundle.properties index ae6a49ac3e4d..5776b6b664b2 100644 --- a/platform/platform-resources-en/src/messages/ExecutionBundle.properties +++ b/platform/platform-resources-en/src/messages/ExecutionBundle.properties @@ -74,6 +74,7 @@ template.settings.configurable.display.name=Template Settings default.run.configuration.name= process.is.running.dialog.title=Process ''{0}'' Is Running +incompatible.configuration.is.running.dialog.title=Incompatible Configuration{0, choice, 1# Is|2#s Are} Running button.disconnect=Disconnect button.terminate=Terminate disconnect.process.confirmation.text=Do you want to disconnect from the process ''{0}''? @@ -162,6 +163,7 @@ run.configuration.use.alternate.jre.checkbox=Use alternative &JRE: run.configuration.select.alternate.jre.label=Select Alternative JRE run.configuration.select.jre.dir.label=Select directory with JRE to run with run.configuration.arguments.help.panel.copy.action.name=Copy +run.configuration.no.name= terminating.process.progress.title=Terminating ''{0}'' terminating.process.progress.kill=Kill process waiting.for.vm.detach.progress.text=Waiting for process detach @@ -170,6 +172,8 @@ rerun.configuration.action.name=Rerun ''{0}'' rerun.singleton.confirmation.message=''{0}'' is single-instance run configuration.\nAre you sure you want to stop {1, choice, 1#the running one|2#{1, number} running instances}? rerun.confirmation.button.text=Stop and Rerun rerun.confirmation.checkbox=Confirm rerun with process termination +stop.incompatible.confirmation.message=''{0}'' run configuration is not compatible with {2, choice, 1#currently running {1} configuration.|2#following running configurations:\n{1}}\nAre you sure you want to stop {2, choice, 1#incompatible running instance|2#{2, number} incompatible running instances}? +stop.incompatible.confirmation.button.text=Stop incompatible run.configuration.dump.threads.action.name=Dump Threads run.configuration.exit.action.name=Exit run.error.message.title=Run Error diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferReplaceableByString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferReplaceableByString.html index 9ab43dec8040..01aab76f96c0 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferReplaceableByString.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferReplaceableByString.html @@ -1,8 +1,10 @@ Reports any variables declared as or uses of java.lang.StringBuffer and java.lang.StringBuilder -which are effectively constant. These may be replaced with java.lang.String expressions which results in simpler and possibly -more efficient code. +which can be replaced with a single java.lang.String concatenation. Using a String concatenation +makes the code shorter and simpler. +This inspection only reports when the resulting concatenation is at least as efficient or more efficient than the original +StringBuffer or StringBuilder use.

diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/DoubleCheckedLockingInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/DoubleCheckedLockingInspectionTest.java new file mode 100644 index 000000000000..45cf3702f3cd --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/DoubleCheckedLockingInspectionTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2014 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.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; + +/** + * @author Bas Leijdekkers + */ +public class DoubleCheckedLockingInspectionTest extends LightInspectionTestCase { + + public void testSimple() { + doTest("class A {" + + " private boolean initialized;\n" + + " private void initialize() {\n" + + " /*Double-checked locking*/if/**/ (initialized == false) {\n" + + " synchronized (this) {\n" + + " if (initialized == false) {\n" + + " initialized = true;\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"); + } + + public void testVolatile() { + doTest("class X {" + + " private volatile boolean initialized;\n" + + " private void initialize() {\n" + + " if (initialized == false) {\n" + + " synchronized (this) {\n" + + " if (initialized == false) {\n" + + " initialized = true;\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"); + } + + @Override + protected InspectionProfileEntry getInspection() { + final DoubleCheckedLockingInspection inspection = new DoubleCheckedLockingInspection(); + inspection.ignoreOnVolatileVariables = true; + return inspection; + } +}