From 5cf2cf24e36cbadbe16fa2a667cf450829ccc306 Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Thu, 20 Oct 2016 21:20:22 +0300 Subject: [PATCH 01/50] A fix for IDEA-162922 Enter action produces 2 undo operations --- .../codeInsight/editorActions/BaseEnterHandler.java | 2 +- .../codeStyle/lineIndent/FormatterBasedIndentAdjuster.java | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BaseEnterHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BaseEnterHandler.java index cbb701d8075c..c1971199c6c7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BaseEnterHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BaseEnterHandler.java @@ -21,7 +21,7 @@ import com.intellij.openapi.editor.actionSystem.DocCommandGroupId; import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler; public abstract class BaseEnterHandler extends EditorWriteActionHandler { - private static final String GROUP_ID = "EnterHandler.GROUP_ID"; + public static final String GROUP_ID = "EnterHandler.GROUP_ID"; protected BaseEnterHandler() { super(false); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedIndentAdjuster.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedIndentAdjuster.java index d800750409d6..cbd8da60ab39 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedIndentAdjuster.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedIndentAdjuster.java @@ -25,8 +25,6 @@ import org.jetbrains.annotations.NotNull; public class FormatterBasedIndentAdjuster { - private static final String ADJUST_INDENT_COMMAND_NAME = "Adjust Indent"; - private FormatterBasedIndentAdjuster() { } @@ -57,10 +55,10 @@ public class FormatterBasedIndentAdjuster { public void run() { int lineStart = myDocument.getLineStartOffset(myLine); - CommandProcessor.getInstance().executeCommand(myProject, () -> + CommandProcessor.getInstance().runUndoTransparentAction(() -> ApplicationManager.getApplication().runWriteAction(() -> { CodeStyleManager.getInstance(myProject).adjustLineIndent(myDocument, lineStart); - }), ADJUST_INDENT_COMMAND_NAME, null); + })); } } From e0cfbf28db492b8e87b4241d25d068a0dbae504d Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Thu, 20 Oct 2016 21:56:59 +0300 Subject: [PATCH 02/50] Hide disabled and invisible actions from "Find Action..." result list --- .../intellij/ide/actions/GotoActionAction.java | 15 +++++++++++++++ .../ide/util/gotoByName/ChooseByNameBase.java | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java index 1b4d89f9d706..4799415d79cb 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java @@ -55,6 +55,7 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.event.*; +import java.util.Iterator; import java.util.Set; public class GotoActionAction extends GotoActionBase implements DumbAware { @@ -97,6 +98,20 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { } final Disposable disposable = Disposer.newDisposable(); final ChooseByNamePopup popup = new ChooseByNamePopup(project, model, new GotoActionItemProvider(model), oldPopup, initialText, false, initialIndex) { + @Override + protected void filterInEDT(Set elements) { + for (Iterator iterator = elements.iterator(); iterator.hasNext(); ) { + Object o = iterator.next(); + if (o instanceof GotoActionModel.MatchedValue) { + Comparable value = ((GotoActionModel.MatchedValue)o).value; + if (value instanceof GotoActionModel.ActionWrapper) { + GotoActionModel.ActionWrapper wrapper = (GotoActionModel.ActionWrapper)value; + if (!wrapper.getPresentation().isEnabled() || !wrapper.getPresentation().isVisible()) iterator.remove(); + } + } + } + } + @Override protected void initUI(Callback callback, ModalityState modalityState, boolean allowMultipleSelection) { super.initUI(callback, modalityState, allowMultipleSelection); diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index b71a4a021d3d..5bc6dca578d4 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -1467,6 +1467,9 @@ public abstract class ChooseByNameBase { return panel; } + protected void filterInEDT(Set elements) { + } + private class CalcElementsThread extends ReadTask { private final String myPattern; private final boolean myCheckboxState; @@ -1518,6 +1521,8 @@ public abstract class ChooseByNameBase { showCard(cardToShow, 0); + filterInEDT(filtered); + myCallback.consume(filtered); } }, myModalityState); From e9563ed106675f8b15b740f4d678a9cbd7547bdb Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 20 Oct 2016 21:41:02 +0200 Subject: [PATCH 03/50] - Provide setting for starting directory (IDEA-125383) - Split settings into project and application parts (IDEA-157148) - Respect changes of the default system shell (IDEA-147227) --- .../terminal/LocalTerminalDirectRunner.java | 17 +- .../terminal/TerminalOptionsConfigurable.java | 7 +- .../terminal/TerminalOptionsProvider.java | 32 -- .../TerminalProjectOptionsProvider.java | 162 +++++++++ .../terminal/TerminalSettingsPanel.form | 317 ++++++++++-------- .../terminal/TerminalSettingsPanel.java | 79 ++++- 6 files changed, 416 insertions(+), 198 deletions(-) create mode 100644 plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalProjectOptionsProvider.java diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java index 1d10271353da..f426ccc4d1a1 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java @@ -24,10 +24,8 @@ import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.process.ProcessWaitFor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.concurrency.AppExecutorUtil; import com.intellij.util.containers.HashMap; @@ -129,24 +127,13 @@ public class LocalTerminalDirectRunner extends AbstractTerminalRunner { + private static final Logger LOG = Logger.getInstance(TerminalProjectOptionsProvider.class); + + private State myState = new State(); + private final Project myProject; + + public TerminalProjectOptionsProvider(Project project) {myProject = project;} + + + public static TerminalProjectOptionsProvider getInstance(@NotNull Project project) { + return ServiceManager.getService(project, TerminalProjectOptionsProvider.class); + } + + @Override + public State getState() { + return myState; + } + + @Override + public void loadState(State state) { + setShellPath(state.myShellPath); + myState.myStartingDirectory = state.myStartingDirectory; + } + + + public static class State { + public String myShellPath = null; + public String myStartingDirectory = null; + } + + public String getShellPath() { + if (myState.myShellPath != null) { + return myState.myShellPath; + } else { + return getDefaultShellPath(); + } + } + + + public void setShellPath(String shellPath) { + if (isShellPathDefault(shellPath) || StringUtil.isEmpty(shellPath)) { + myState.myShellPath = null; + } else { + myState.myShellPath = shellPath; + } + } + + + public void setStartingDirectory(String startingDirectory) { + if (isStartingDirectoryDefault(startingDirectory) || StringUtil.isEmpty(startingDirectory)) { + myState.myStartingDirectory = null; + } else { + myState.myStartingDirectory = startingDirectory; + } + } + + public boolean isShellPathDefault(String shellPath) { + return StringUtil.equals(shellPath, getDefaultShellPath()); + } + + public boolean isStartingDirectoryDefault(String startingDirectory) { + return StringUtil.equals(startingDirectory, getDefaultStartingDirectory()); + } + + public String getStartingDirectory() { + if (myState.myStartingDirectory != null) { + return myState.myStartingDirectory; + } + else { + return getDefaultStartingDirectory(); + } + } + + + private static String getDefaultShellPath() { + String shell = System.getenv("SHELL"); + + if (shell != null && new File(shell).canExecute()) { + return shell; + } + + if (SystemInfo.isUnix) { + if (new File("/bin/bash").exists()) { + return "/bin/bash"; + } + else { + return "/bin/sh"; + } + } + else { + return "cmd.exe"; + } + } + + public String getDefaultStartingDirectory() { + String directory = null; + for (LocalTerminalCustomizer customizer : LocalTerminalCustomizer.EP_NAME.getExtensions()) { + try { + + if (directory == null) { + directory = customizer.getDefaultFolder(); + } + } + catch (Exception e) { + LOG.error("Exception during getting default folder", e); + } + } + + return currentProjectFolder(); + } + + + private String currentProjectFolder() { + final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(myProject); + + final VirtualFile[] roots = projectRootManager.getContentRoots(); + if (roots.length == 1) { + roots[0].getCanonicalPath(); + } + final VirtualFile baseDir = myProject.getBaseDir(); + return baseDir == null ? null : baseDir.getCanonicalPath(); + } +} + diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.form b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.form index af3c82b03bad..f8963c843dd9 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.form +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.form @@ -3,12 +3,12 @@ - + - + @@ -19,7 +19,12 @@ - + + + + + + @@ -36,37 +41,30 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - + @@ -74,23 +72,37 @@ - + + - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + @@ -110,121 +122,144 @@ - - - - - - - - - - - + + - + - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.java index 66c0da8664de..1ae6c15aabb9 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.java +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalSettingsPanel.java @@ -19,10 +19,15 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.ui.TextComponentAccessor; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Comparing; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.components.JBCheckBox; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.event.DocumentEvent; +import java.awt.*; +import java.util.Arrays; /** * @author traff @@ -38,27 +43,61 @@ public class TerminalSettingsPanel { private JBCheckBox myCopyOnSelectionCheckBox; private JBCheckBox myOverrideIdeShortcuts; private JBCheckBox myShellIntegration; + private TextFieldWithBrowseButton myStartDirectoryField; + private JPanel myProjectSettingsPanel; + private JPanel myGlobalSettingsPanel; private TerminalOptionsProvider myOptionsProvider; + private TerminalProjectOptionsProvider myProjectOptionsProvider; - public JComponent createPanel(@NotNull TerminalOptionsProvider provider) { + public JComponent createPanel(@NotNull TerminalOptionsProvider provider, @NotNull TerminalProjectOptionsProvider projectOptionsProvider) { myOptionsProvider = provider; + myProjectOptionsProvider = projectOptionsProvider; + + myProjectSettingsPanel.setBorder(IdeBorderFactory.createTitledBorder("Project settings")); + myGlobalSettingsPanel.setBorder(IdeBorderFactory.createTitledBorder("Application settings")); FileChooserDescriptor fileChooserDescriptor = new FileChooserDescriptor(true, false, false, false, false, false); myShellPathField.addBrowseFolderListener( "", - "Shell Executable Path", + "Shell executable path", null, fileChooserDescriptor, - TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT, - false - ); + TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT); + + fileChooserDescriptor = new FileChooserDescriptor(false, true, false, false, false, false); + + myStartDirectoryField.addBrowseFolderListener( + "", + "Starting directory", + null, + fileChooserDescriptor, + TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT); + + myShellPathField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + myShellPathField + .getTextField().setForeground(myProjectOptionsProvider.isShellPathDefault(myShellPathField.getText()) ? + getDefaultValueColor() : getChangedValueColor()); + } + }); + + myStartDirectoryField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + myStartDirectoryField + .getTextField().setForeground(myProjectOptionsProvider.isStartingDirectoryDefault(myStartDirectoryField.getText()) ? + getDefaultValueColor() : getChangedValueColor()); + } + }); return myWholePanel; } public boolean isModified() { - return !Comparing.equal(myShellPathField.getText(), myOptionsProvider.getShellPath()) + return !Comparing.equal(myShellPathField.getText(), myProjectOptionsProvider.getShellPath()) + || !Comparing.equal(myStartDirectoryField.getText(), myProjectOptionsProvider.getStartingDirectory()) || !Comparing.equal(myTabNameTextField.getText(), myOptionsProvider.getTabName()) || (myCloseSessionCheckBox.isSelected() != myOptionsProvider.closeSessionOnLogout()) || (myMouseReportCheckBox.isSelected() != myOptionsProvider.enableMouseReporting()) @@ -71,7 +110,8 @@ public class TerminalSettingsPanel { } public void apply() { - myOptionsProvider.setShellPath(myShellPathField.getText()); + myProjectOptionsProvider.setShellPath(myShellPathField.getText()); + myProjectOptionsProvider.setStartingDirectory(myStartDirectoryField.getText()); myOptionsProvider.setTabName(myTabNameTextField.getText()); myOptionsProvider.setCloseSessionOnLogout(myCloseSessionCheckBox.isSelected()); myOptionsProvider.setReportMouse(myMouseReportCheckBox.isSelected()); @@ -83,7 +123,8 @@ public class TerminalSettingsPanel { } public void reset() { - myShellPathField.setText(myOptionsProvider.getShellPath()); + myShellPathField.setText(myProjectOptionsProvider.getShellPath()); + myStartDirectoryField.setText(myProjectOptionsProvider.getStartingDirectory()); myTabNameTextField.setText(myOptionsProvider.getTabName()); myCloseSessionCheckBox.setSelected(myOptionsProvider.closeSessionOnLogout()); myMouseReportCheckBox.setSelected(myOptionsProvider.enableMouseReporting()); @@ -93,4 +134,26 @@ public class TerminalSettingsPanel { myOverrideIdeShortcuts.setSelected(myOptionsProvider.overrideIdeShortcuts()); myShellIntegration.setSelected(myOptionsProvider.shellIntegration()); } + + public Color getDefaultValueColor() { + return findColorByKey("TextField.inactiveForeground", "nimbusDisabledText"); + } + + @NotNull + private static Color findColorByKey(String... colorKeys) { + Color c = null; + for (String key : colorKeys) { + c = UIManager.getColor(key); + if (c != null) { + break; + } + } + + assert c != null : "Can't find color for keys " + Arrays.toString(colorKeys); + return c; + } + + public Color getChangedValueColor() { + return findColorByKey("TextField.foreground"); + } } From 9f2b0f3a339b4b11d9d9a033eecb7d6b3b49e8d2 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 20 Oct 2016 23:35:30 +0300 Subject: [PATCH 04/50] type migration: fix some warnings --- .../MigrateGetterNameSetting.java | 37 +++++++++---------- .../TypeConversionDescriptorBase.java | 9 ----- .../typeMigration/TypeEvaluator.java | 4 +- .../typeMigration/TypeMigrationLabeler.java | 23 ++++++------ .../typeMigration/TypeMigrationProcessor.java | 5 +-- .../TypeMigrationStatementProcessor.java | 6 +-- .../actions/ChangeTypeSignatureAction.java | 6 --- .../rules/RootTypeConversionRule.java | 4 +- .../ui/FailedConversionsDialog.java | 2 +- .../typeMigration/ui/MigrationNode.java | 4 -- .../typeMigration/ui/MigrationPanel.java | 16 ++++---- .../typeMigration/ui/MigrationRootNode.java | 2 +- ...sageInfo.java => OverriddenUsageInfo.java} | 4 +- 13 files changed, 48 insertions(+), 74 deletions(-) rename java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/{OverridenUsageInfo.java => OverriddenUsageInfo.java} (89%) diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/MigrateGetterNameSetting.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/MigrateGetterNameSetting.java index a8a76800dc90..36dd706410cc 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/MigrateGetterNameSetting.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/MigrateGetterNameSetting.java @@ -19,7 +19,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.ui.Messages; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiType; -import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo; +import com.intellij.refactoring.typeMigration.usageInfo.OverriddenUsageInfo; import com.intellij.util.ui.UIUtil; import java.util.concurrent.atomic.AtomicReference; @@ -34,7 +34,7 @@ class MigrateGetterNameSetting { private final AtomicReference myGlobalValue = new AtomicReference<>(); - void askUserIfNeed(final OverridenUsageInfo info, final String newMethodName, final PsiType migrationReturnType) { + void askUserIfNeed(final OverriddenUsageInfo info, final String newMethodName, final PsiType migrationReturnType) { final Boolean globalValue = myGlobalValue.get(); if (globalValue == null) { final String currentName = ((PsiMethod)info.getElement()).getName(); @@ -42,26 +42,23 @@ class MigrateGetterNameSetting { currentName, newMethodName, migrationReturnType.getCanonicalText()); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - final Boolean globalValue = myGlobalValue.get(); - if (globalValue == null) { - final int code = showChooserDialog(messageText); - if (code == 0) { - myGlobalValue.set(true); - info.setMigrateMethodName(newMethodName); - } - else if (code == 1) { - info.setMigrateMethodName(newMethodName); - } - else if (code == 2) { - myGlobalValue.set(false); - } - } - else if (globalValue.equals(Boolean.TRUE)) { + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + final Boolean globalValue1 = myGlobalValue.get(); + if (globalValue1 == null) { + final int code = showChooserDialog(messageText); + if (code == 0) { + myGlobalValue.set(true); info.setMigrateMethodName(newMethodName); } + else if (code == 1) { + info.setMigrateMethodName(newMethodName); + } + else if (code == 2) { + myGlobalValue.set(false); + } + } + else if (globalValue1.equals(Boolean.TRUE)) { + info.setMigrateMethodName(newMethodName); } }); } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptorBase.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptorBase.java index 5213fadd83ee..a3c68a6abcc7 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptorBase.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptorBase.java @@ -46,15 +46,6 @@ public class TypeConversionDescriptorBase { return null; } - /** - * @return substitutor of converted method parameters - * or null if expression is not method call expression - */ - @Nullable - public PsiSubstitutor getConvertedMethodParameters() { - return null; - } - public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException { return expression; } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java index aef757746501..7bbea4a2bca3 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeEvaluator.java @@ -348,14 +348,14 @@ public class TypeEvaluator { } public String getReport() { - final StringBuffer buffer = new StringBuffer(); + final StringBuilder buffer = new StringBuilder(); final String[] t = new String[myTypeMap.size()]; int k = 0; for (final TypeMigrationUsageInfo info : myTypeMap.keySet()) { final LinkedList types = myTypeMap.get(info); - final StringBuffer b = new StringBuffer(); + final StringBuilder b = new StringBuilder(); if (types != null) { b.append(info.getElement()).append(" : "); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java index cdba34131b75..0ea58844270f 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java @@ -38,7 +38,7 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.rename.RenameProcessor; import com.intellij.refactoring.typeCook.deductive.PsiExtendedTypeVisitor; -import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo; +import com.intellij.refactoring.typeMigration.usageInfo.OverriddenUsageInfo; import com.intellij.refactoring.typeMigration.usageInfo.OverriderUsageInfo; import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo; import com.intellij.usageView.UsageInfo; @@ -88,7 +88,7 @@ public class TypeMigrationLabeler { private final Set myProcessedRoots = new HashSet<>(); public TypeMigrationLabeler(final TypeMigrationRules rules, PsiType rootType) { - this(rules, Functions.constant(rootType)); + this(rules, Functions.constant(rootType)); } public TypeMigrationLabeler(final TypeMigrationRules rules, Function migrationRootTypeFunction) { @@ -339,8 +339,8 @@ public class TypeMigrationLabeler { } else { TypeMigrationReplacementUtil.migrateMemberOrVariableType(element, project, getTypeEvaluator().getType(usageInfo)); - if (usageInfo instanceof OverridenUsageInfo) { - final String migrationName = ((OverridenUsageInfo)usageInfo).getMigrateMethodName(); + if (usageInfo instanceof OverriddenUsageInfo) { + final String migrationName = ((OverriddenUsageInfo)usageInfo).getMigrateMethodName(); if (migrationName != null) { ApplicationManager.getApplication().invokeLater(() -> new RenameProcessor(project, element, migrationName, false, false).run()); } @@ -662,12 +662,12 @@ public class TypeMigrationLabeler { for (int i = -1; i < methods.length; i++) { final TypeMigrationUsageInfo m; if (i < 0) { - final OverridenUsageInfo overridenUsageInfo = new OverridenUsageInfo(method); - m = overridenUsageInfo; + final OverriddenUsageInfo overriddenUsageInfo = new OverriddenUsageInfo(method); + m = overriddenUsageInfo; final String newMethodName = isMethodNameCanBeChanged(method); if (newMethodName != null) { final MigrateGetterNameSetting migrateGetterNameSetting = myRules.getConversionSettings(MigrateGetterNameSetting.class); - migrateGetterNameSetting.askUserIfNeed(overridenUsageInfo, newMethodName, myTypeEvaluator.getType(myCurrentRoot)); + migrateGetterNameSetting.askUserIfNeed(overriddenUsageInfo, newMethodName, myTypeEvaluator.getType(myCurrentRoot)); } } else { @@ -687,13 +687,13 @@ public class TypeMigrationLabeler { final PsiMethod[] methods = OverridingMethodsSearch.search(method).toArray(PsiMethod.EMPTY_ARRAY); final OverriderUsageInfo[] overriders = new OverriderUsageInfo[methods.length]; - final OverridenUsageInfo overridenUsageInfo = new OverridenUsageInfo(method.getParameterList().getParameters()[index]); + final OverriddenUsageInfo overriddenUsageInfo = new OverriddenUsageInfo(method.getParameterList().getParameters()[index]); for (int i = -1; i < methods.length; i++) { final PsiMethod m = i < 0 ? method : methods[i]; final PsiParameter p = m.getParameterList().getParameters()[index]; final TypeMigrationUsageInfo paramUsageInfo; if (i < 0) { - paramUsageInfo = overridenUsageInfo; + paramUsageInfo = overriddenUsageInfo; } else { overriders[i] = new OverriderUsageInfo(p, method); @@ -924,7 +924,7 @@ public class TypeMigrationLabeler { } } - Collections.sort(validReferences, (o1, o2) -> o1.getElement().getTextOffset() - o2.getElement().getTextOffset()); + Collections.sort(validReferences, Comparator.comparingInt(o -> o.getElement().getTextOffset())); return validReferences.toArray(new PsiReference[validReferences.size()]); } @@ -1040,8 +1040,7 @@ public class TypeMigrationLabeler { } private void iterate() { - final LinkedList> roots = - (LinkedList>)myMigrationRoots.clone(); + final List> roots = new ArrayList<>(myMigrationRoots); myMigrationRoots = new LinkedList<>(); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java index d8d2fbefc036..9ddcf9b03aa8 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java @@ -45,11 +45,10 @@ import java.util.*; import static com.intellij.util.ObjectUtils.assertNotNull; public class TypeMigrationProcessor extends BaseRefactoringProcessor { - private final static Logger LOG = Logger.getInstance(TypeMigrationProcessor.class); private final static int MAX_ROOT_IN_PREVIEW_PRESENTATION = 3; private PsiElement[] myRoot; - private Function myRootTypes; + private final Function myRootTypes; private final TypeMigrationRules myRules; private TypeMigrationLabeler myLabeler; @@ -74,7 +73,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor { final PsiElement root, final PsiType migrationType, final boolean optimizeImports) { - runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.constant(migrationType), optimizeImports); + runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.constant(migrationType), optimizeImports); } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java index f58f2eb585d4..80ab5601ed58 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java @@ -202,7 +202,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { final PsiType valueType = myTypeEvaluator.evaluateType(value); if (returnType != null && valueType != null) { if (!myLabeler.addMigrationRoot(method, valueType, myStatement, TypeConversionUtil.isAssignable(returnType, valueType) && !isGetter(value, method), true, true) - && TypeMigrationLabeler.typeContainsTypeParameters(returnType, Collections.emptySet())) { + && TypeMigrationLabeler.typeContainsTypeParameters(returnType, Collections.emptySet())) { value.accept(this); } } @@ -638,7 +638,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { PsiType type = myTypeEvaluator.evaluateType(expr); type = type instanceof PsiEllipsisType ? ((PsiEllipsisType)type).toArrayType() : type; myType = GenericsUtil.getVariableTypeByExpressionType(type); - myChanged = (myOriginType == null || myType == null) ? false : !myType.equals(myOriginType); + myChanged = !(myOriginType == null || myType == null) && !myType.equals(myOriginType); } public TypeView(PsiVariable var, PsiSubstitutor varSubstitutor, PsiSubstitutor evalSubstitutor) { @@ -649,7 +649,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { if (evalSubstitutor != null) realMap.putAll(evalSubstitutor.getSubstitutionMap()); myType = PsiSubstitutorImpl.createSubstitutor(realMap).substitute(myTypeEvaluator.getType(var)); - myChanged = (myOriginType == null || myType == null) ? false : !myType.equals(myOriginType); + myChanged = !(myOriginType == null || myType == null) && !myType.equals(myOriginType); } public PsiType getType() { diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/actions/ChangeTypeSignatureAction.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/actions/ChangeTypeSignatureAction.java index 943acea256d9..98fe842aeb75 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/actions/ChangeTypeSignatureAction.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/actions/ChangeTypeSignatureAction.java @@ -34,12 +34,6 @@ public class ChangeTypeSignatureAction extends BaseRefactoringAction { } public boolean isEnabledOnElements(@NotNull PsiElement[] elements) { - Project currProject = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext()); - - if (currProject == null) { - return false; - } - if (elements.length > 1) return false; for (PsiElement element : elements) { diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/rules/RootTypeConversionRule.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/rules/RootTypeConversionRule.java index a4895d63f747..7c4551fe8466 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/rules/RootTypeConversionRule.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/rules/RootTypeConversionRule.java @@ -65,7 +65,7 @@ public class RootTypeConversionRule extends TypeConversionRule { if (Comparing.equal(functionalInterfaceType, to) && method.isEquivalentTo(LambdaUtil.getFunctionalInterfaceMethod(from))) { return new TypeConversionDescriptorBase() { @Override - public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) throws IncorrectOperationException { + public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException { final PsiMethodReferenceExpression methodReferenceExpression = (PsiMethodReferenceExpression)expression; final PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression(); if (qualifierExpression != null) { @@ -147,7 +147,7 @@ public class RootTypeConversionRule extends TypeConversionRule { } @Override - public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) throws IncorrectOperationException { + public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException { final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(expression.getProject()); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/FailedConversionsDialog.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/FailedConversionsDialog.java index 103375899e33..2a845ac7254a 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/FailedConversionsDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/FailedConversionsDialog.java @@ -59,7 +59,7 @@ public class FailedConversionsDialog extends DialogWrapper { panel.add(new JLabel(RefactoringBundle.message("the.following.problems.were.found")), BorderLayout.NORTH); panel.add(scrollPane, BorderLayout.CENTER); - @NonNls StringBuffer buf = new StringBuffer(); + @NonNls StringBuilder buf = new StringBuilder(); for (String description : myConflictDescriptions) { buf.append(description); buf.append("

"); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationNode.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationNode.java index d8e6ea77a044..53252e161482 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationNode.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationNode.java @@ -121,8 +121,4 @@ public class MigrationNode extends AbstractTreeNode impl public MigrationNode getDuplicate() { return myDuplicatedNode; } - - public boolean hasDuplicate() { - return myDuplicatedNode != null; - } } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java index bc42a40658db..3173cc671b4e 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java @@ -187,15 +187,14 @@ public class MigrationPanel extends JPanel implements Disposable { if (userObject instanceof MigrationRootNode) { ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> { final HashSet files = new HashSet<>(); - final TypeMigrationUsageInfo[] usages = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public TypeMigrationUsageInfo[] compute() { + final TypeMigrationUsageInfo[] usages = ApplicationManager.getApplication().runReadAction( + (Computable)() -> { final Collection children = ((MigrationRootNode)userObject).getChildren(); for (AbstractTreeNode child : children) { expandTree((MigrationNode)child); } - final TypeMigrationUsageInfo[] usages = myLabeler.getMigratedUsages(); - for (TypeMigrationUsageInfo usage : usages) { + final TypeMigrationUsageInfo[] usages1 = myLabeler.getMigratedUsages(); + for (TypeMigrationUsageInfo usage : usages1) { if (!usage.isExcluded()) { final PsiElement element = usage.getElement(); if (element != null) { @@ -203,9 +202,8 @@ public class MigrationPanel extends JPanel implements Disposable { } } } - return usages; - } - }); + return usages1; + }); ApplicationManager.getApplication().invokeLater(() -> { @@ -306,7 +304,7 @@ public class MigrationPanel extends JPanel implements Disposable { } public Object getData(@NonNls final String dataId) { - if (DataConstants.PSI_ELEMENT.equals(dataId)) { + if (CommonDataKeys.PSI_ELEMENT.is(dataId)) { final DefaultMutableTreeNode[] selectedNodes = getSelectedNodes(DefaultMutableTreeNode.class, null); return selectedNodes.length == 1 && selectedNodes[0].getUserObject() instanceof MigrationNode ? ((MigrationNode)selectedNodes[0].getUserObject()).getInfo().getElement() : null; diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationRootNode.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationRootNode.java index 8c210503e0b2..06cc4b736259 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationRootNode.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationRootNode.java @@ -37,7 +37,7 @@ import java.util.*; public class MigrationRootNode extends AbstractTreeNode implements DuplicateNodeRenderer.DuplicatableNode { private final TypeMigrationLabeler myLabeler; private List myCachedChildren; - private final PsiElement myRoots[]; + private final PsiElement[] myRoots; private final boolean myPreviewUsages; protected MigrationRootNode(Project project, diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverridenUsageInfo.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverriddenUsageInfo.java similarity index 89% rename from java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverridenUsageInfo.java rename to java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverriddenUsageInfo.java index 3d72c7dad553..cd2ee0a635c3 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverridenUsageInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/usageInfo/OverriddenUsageInfo.java @@ -22,10 +22,10 @@ import org.jetbrains.annotations.NotNull; * @author anna * Date: 27-Mar-2008 */ -public class OverridenUsageInfo extends TypeMigrationUsageInfo { +public class OverriddenUsageInfo extends TypeMigrationUsageInfo { private volatile String myMigrateMethodName; - public OverridenUsageInfo(@NotNull PsiElement element) { + public OverriddenUsageInfo(@NotNull PsiElement element) { super(element); } From 8f232a91739011ec2906a25a583e69f367e0bfe8 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Thu, 20 Oct 2016 05:10:52 +0300 Subject: [PATCH 05/50] [git] more diagnostic for EA-62663 --- plugins/git4idea/src/git4idea/history/GitHistoryUtils.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index b2f721479513..74e7cc0066f5 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -840,7 +840,9 @@ public class GitHistoryUtils { Collection refsInRecord = parseRefs(record.getRefs(), commit.getId(), factory, root); for (VcsRef ref : refsInRecord) { if (!refs.add(ref)) { - LOG.error("Adding duplicate element to the set"); + // relying on the fact that intersection method puts elements of the first argument into the result + VcsRef otherRef = ContainerUtil.getFirstItem(ContainerUtil.intersection(refs, Collections.singleton(ref))); + LOG.error("Adding duplicate element " + ref + " to the set containing " + otherRef); } } return commit; From bc8f03f8ff44a15abbb93abec7dcb90bee0b24d5 Mon Sep 17 00:00:00 2001 From: Vyacheslav Karpukhin Date: Fri, 21 Oct 2016 00:11:13 +0200 Subject: [PATCH 06/50] Added AppLifecycleListener.appWilExit API --- .../src/com/intellij/ide/AppLifecycleListener.java | 5 +++++ .../intellij/openapi/application/impl/ApplicationImpl.java | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ide/AppLifecycleListener.java b/platform/platform-impl/src/com/intellij/ide/AppLifecycleListener.java index 0dbb49745959..8adc41706d78 100644 --- a/platform/platform-impl/src/com/intellij/ide/AppLifecycleListener.java +++ b/platform/platform-impl/src/com/intellij/ide/AppLifecycleListener.java @@ -55,6 +55,11 @@ public interface AppLifecycleListener { */ void appClosing(); + /** + * Fired after all exit checks and after saving the settings. At this point the app is guaranteed to exit. + */ + default void appWillExit() { } + abstract class Adapter implements AppLifecycleListener { @Override public void appFrameCreated(String[] commandLineArgs, @NotNull Ref willOpenProject) { } diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index bf3580c55a03..2afffcfcf373 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -758,7 +758,8 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App return; } - getMessageBus().syncPublisher(AppLifecycleListener.TOPIC).appClosing(); + final AppLifecycleListener publisher = getMessageBus().syncPublisher(AppLifecycleListener.TOPIC); + publisher.appClosing(); myDisposeInProgress = true; @@ -768,6 +769,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App saveSettings(); + publisher.appWillExit(); boolean success = disposeSelf(!force); if (!success || isUnitTestMode() || Boolean.getBoolean("idea.test.guimode")) { From 8c6088647baae31b2a92262a36d546c69adeb402 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 21 Oct 2016 12:10:10 +0700 Subject: [PATCH 07/50] IDEA-162875 Stream API migration: support conversion to BufferedReader.lines() --- .../streamMigration/MigrateToStreamFix.java | 1 + .../StreamApiMigrationInspection.java | 144 +++++++++++++++++- .../psi/controlFlow/ControlFlowUtil.java | 83 +++++----- .../afterBufferedReaderCollect.java | 15 ++ .../afterBufferedReaderCollectNestedOk.java | 19 +++ .../afterBufferedReaderSum.java | 11 ++ .../beforeBufferedReaderCollect.java | 17 +++ .../beforeBufferedReaderCollectNested.java | 19 +++ .../beforeBufferedReaderCollectNestedOk.java | 21 +++ .../beforeBufferedReaderModifiedLine.java | 16 ++ .../beforeBufferedReaderSum.java | 16 ++ .../beforeBufferedReaderSumLineReused.java | 16 ++ .../Convert2streamapi.html | 2 +- resources/src/META-INF/IdeaPlugin.xml | 2 +- 14 files changed, 328 insertions(+), 54 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollect.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollectNestedOk.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderSum.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollect.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNested.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNestedOk.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSum.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSumLineReused.java diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/MigrateToStreamFix.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/MigrateToStreamFix.java index 2bdbe16a8973..2a34ec766033 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/MigrateToStreamFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/MigrateToStreamFix.java @@ -56,6 +56,7 @@ abstract class MigrateToStreamFix implements LocalQuickFix { if (!FileModificationService.getInstance().preparePsiElementForWrite(loopStatement)) return; PsiElement result = migrate(project, loopStatement, body, tb); if(result != null) { + source.cleanUpSource(); simplifyAndFormat(project, result); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java index 13281bd34db4..e0506fa893ee 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java @@ -390,7 +390,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo return consumerClass != null ? psiFacade.getElementFactory().createType(consumerClass, variable.getType()) : null; } - static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement) { + static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement, StreamSource source) { PsiElement declaration = variable.getParent(); // For-loop initializer is not effectively final, but suitable for stream conversion if(declaration instanceof PsiDeclarationStatement) { @@ -408,6 +408,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } } } + if(statement instanceof PsiWhileStatement && source.getVariable() == variable) { + return ReferencesSearch.search(variable, variable.getUseScope()).forEach(ref -> { + PsiElement element = ref.getElement(); + return !(element instanceof PsiExpression) || + PsiTreeUtil.isAncestor(((PsiWhileStatement)statement).getCondition(), element, false) || + !PsiUtil.isAccessedForWriting((PsiExpression)element); + }); + } return HighlightControlFlowUtil.isEffectivelyFinal(variable, statement, null); } @@ -429,6 +437,58 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo return null; } + /** + * Checks whether variable can be referenced between start and loop entry. Back-edges are also considered, so the actual place + * where it referenced might be outside of (start, loop entry) interval. + * + * @param flow ControlFlow to analyze + * @param start start point + * @param loop loop to check + * @param variable variable to analyze + * @return true if variable can be referenced between start and stop points + */ + private static boolean isVariableReferencedBeforeLoopEntry(final ControlFlow flow, + final int start, + final PsiLoopStatement loop, + final PsiVariable variable) { + final int loopStart = flow.getStartOffset(loop); + final int loopEnd = flow.getEndOffset(loop); + if(start == loopStart) return false; + + List edges = ControlFlowUtil.getEdges(flow, start); + // DFS visits instructions mainly in backward direction while here visiting in forward direction + // greatly reduces number of iterations. + Collections.reverse(edges); + + BitSet referenced = new BitSet(); + boolean changed = true; + while(changed) { + changed = false; + for(ControlFlowUtil.ControlFlowEdge edge: edges) { + int from = edge.myFrom; + int to = edge.myTo; + if(referenced.get(from)) { + // jump to the loop start from within the loop is not considered as loop entry + if(to == loopStart && (from < loopStart || from >= loopEnd)) { + return true; + } + if(!referenced.get(to)) { + referenced.set(to); + changed = true; + } + continue; + } + if(ControlFlowUtil.isVariableAccess(flow, from, variable)) { + referenced.set(from); + referenced.set(to); + if(to == loopStart) return true; + changed = true; + } + } + } + return false; + } + enum InitializerUsageStatus { // Variable is declared just before the wanted place DECLARED_JUST_BEFORE, @@ -440,7 +500,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo UNKNOWN } - static InitializerUsageStatus getInitializerUsageStatus(PsiVariable var, PsiStatement nextStatement) { + static InitializerUsageStatus getInitializerUsageStatus(PsiVariable var, PsiLoopStatement nextStatement) { if(!(var instanceof PsiLocalVariable) || var.getInitializer() == null) return UNKNOWN; if(isDeclarationJustBefore(var, nextStatement)) return DECLARED_JUST_BEFORE; // Check that variable is declared in the same method or the same lambda expression @@ -458,7 +518,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } int start = controlFlow.getEndOffset(var.getInitializer())+1; int stop = controlFlow.getStartOffset(nextStatement); - if(ControlFlowUtil.isVariableReferencedBetween(controlFlow, start, stop, var)) return UNKNOWN; + if(isVariableReferencedBeforeLoopEntry(controlFlow, start, nextStatement, var)) return UNKNOWN; if (!ControlFlowUtil.isValueUsedWithoutVisitingStop(controlFlow, start, stop, var)) return AT_WANTED_PLACE_ONLY; return var.hasModifierProperty(PsiModifier.FINAL) ? UNKNOWN : AT_WANTED_PLACE; } @@ -494,6 +554,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo processLoop(statement); } + @Override + public void visitWhileStatement(PsiWhileStatement statement) { + super.visitWhileStatement(statement); + processLoop(statement); + } + @Override public void visitForStatement(PsiForStatement statement) { super.visitForStatement(statement); @@ -524,7 +590,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo int startOffset = controlFlow.getStartOffset(body); int endOffset = controlFlow.getEndOffset(body); final List nonFinalVariables = StreamEx.of(ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset)) - .remove(variable -> isVariableSuitableForStream(variable, statement)).toList(); + .remove(variable -> isVariableSuitableForStream(variable, statement, source)).toList(); if (exitPoints.isEmpty()) { if(getIncrementedVariable(tb, nonFinalVariables) != null) { @@ -679,6 +745,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo PsiStatement initialization = ((PsiForStatement)statement).getInitialization(); LOG.assertTrue(initialization != null); return initialization.getTextRange(); + } else if(statement instanceof PsiWhileStatement) { + PsiJavaToken rParenth = ((PsiWhileStatement)statement).getRParenth(); + if (wholeStatement && rParenth != null) { + return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1); + } + return statement.getFirstChild().getTextRange(); } else { throw new IllegalStateException("Unexpected statement type: "+statement); } @@ -964,6 +1036,9 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo super(null, expression, variable); } + void cleanUpSource() { + } + @Contract("null -> null") static StreamSource tryCreate(PsiLoopStatement statement) { if(statement instanceof PsiForStatement) { @@ -973,10 +1048,69 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo ArrayStream source = ArrayStream.from((PsiForeachStatement)statement); return source == null ? CollectionStream.from((PsiForeachStatement)statement) : source; } + if(statement instanceof PsiWhileStatement) { + return BufferedReaderLines.from((PsiWhileStatement)statement); + } return null; } } + static class BufferedReaderLines extends StreamSource { + private BufferedReaderLines(PsiVariable variable, PsiExpression expression) { + super(variable, expression); + } + + @Override + String createReplacement() { + return myExpression.getText()+".lines()"; + } + + @Override + void cleanUpSource() { + myVariable.delete(); + } + + @Nullable + public static BufferedReaderLines from(PsiWhileStatement whileLoop) { + // while ((line = br.readLine()) != null) + PsiExpression condition = PsiUtil.skipParenthesizedExprDown(whileLoop.getCondition()); + if(!(condition instanceof PsiBinaryExpression)) return null; + PsiBinaryExpression binOp = (PsiBinaryExpression)condition; + if(!JavaTokenType.NE.equals(binOp.getOperationTokenType())) return null; + PsiExpression operand = null; + if(ExpressionUtils.isNullLiteral(binOp.getROperand())) { + operand = binOp.getLOperand(); + } else if(ExpressionUtils.isNullLiteral(binOp.getLOperand())) { + operand = binOp.getROperand(); + } + if(operand == null) return null; + PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(PsiUtil.skipParenthesizedExprDown(operand)); + if(assignment == null) return null; + PsiExpression lValue = assignment.getLExpression(); + if(!(lValue instanceof PsiReferenceExpression)) return null; + PsiElement element = ((PsiReferenceExpression)lValue).resolve(); + if(!(element instanceof PsiLocalVariable)) return null; + PsiLocalVariable var = (PsiLocalVariable)element; + if(!ReferencesSearch.search(var, var.getUseScope()).forEach(ref -> { + return PsiTreeUtil.isAncestor(whileLoop, ref.getElement(), true); + })) { + return null; + } + PsiExpression rValue = PsiUtil.skipParenthesizedExprDown(assignment.getRExpression()); + if(!(rValue instanceof PsiMethodCallExpression)) return null; + PsiMethodCallExpression call = (PsiMethodCallExpression)rValue; + if(call.getArgumentList().getExpressions().length != 0) return null; + if(!"readLine".equals(call.getMethodExpression().getReferenceName())) return null; + PsiExpression readerExpression = call.getMethodExpression().getQualifierExpression(); + if(readerExpression == null) return null; + PsiMethod method = call.resolveMethod(); + if(method == null) return null; + PsiClass aClass = method.getContainingClass(); + if(aClass == null || !"java.io.BufferedReader".equals(aClass.getQualifiedName())) return null; + return new BufferedReaderLines(var, readerExpression); + } + } + static class ArrayStream extends StreamSource { private ArrayStream(PsiVariable variable, PsiExpression expression) { super(variable, expression); @@ -1224,7 +1358,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo if(source == null || body == null) return null; // flatMap from primitive to primitive is supported only if primitive types match // otherwise it would be necessary to create bogus step like - // .mapToObj(var -> blahblah.stream()).flatMap(Function.identity()) + // .mapToObj(var -> collection.stream()).flatMap(Function.identity()) if(myVariable.getType() instanceof PsiPrimitiveType && !myVariable.getType().equals(source.getVariable().getType())) return null; FlatMapOp op = new FlatMapOp(myPreviousOp, source, myVariable, loopStatement); TerminalBlock withFlatMap = new TerminalBlock(op, source.getVariable(), body); diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java index ddab945cff0f..4e66505942e4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java @@ -29,7 +29,6 @@ import com.intellij.util.containers.IntArrayList; import com.intellij.util.containers.IntStack; import gnu.trove.THashMap; import gnu.trove.THashSet; -import gnu.trove.TIntArrayList; import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -1330,30 +1329,47 @@ public class ControlFlowUtil { } /** - * Checks whether variable can be referenced between start and stop points. Back-edges are also considered, so the actual place - * where it referenced might be outside of (start, stop) interval. + * Checks if the control flow instruction at given offset accesses (reads or writes) given variable * - * @param flow ControlFlow to analyze - * @param start start point - * @param stop stop point - * @param variable variable to analyze - * @return true if variable can be referenced between start and stop points + * @param flow control flow + * @param offset offset inside given control flow + * @param variable a variable the access to which is to be checked + * @return true if the given instruction is actually a variable access */ - public static boolean isVariableReferencedBetween(final ControlFlow flow, - final int start, - final int stop, - final PsiVariable variable) { - if(start == stop) return false; + public static boolean isVariableAccess(ControlFlow flow, int offset, PsiVariable variable) { + Instruction instruction = flow.getInstructions().get(offset); + return instruction instanceof ReadVariableInstruction && ((ReadVariableInstruction)instruction).variable == variable || + instruction instanceof WriteVariableInstruction && ((WriteVariableInstruction)instruction).variable == variable; + } - // DFS visits instructions mainly in backward direction while here visiting in forward direction - // greatly reduces number of iterations. So first we just collect edges, then reverse their order. - // contains (from, to) pairs representing control flow arcs - final TIntArrayList list = new TIntArrayList(); + public static class ControlFlowEdge { + public final int myFrom; + public final int myTo; + + public ControlFlowEdge(int from, int to) { + myFrom = from; + myTo = to; + } + + @Override + public String toString() { + return myFrom+"->"+myTo; + } + } + + /** + * Returns control flow edges which are potentially reachable from start instruction + * + * @param flow control flow to analyze + * @param start starting instruction offset + * @return a list of edges + */ + public static List getEdges(ControlFlow flow, int start) { + final List list = new ArrayList(); depthFirstSearch(flow, new InstructionClientVisitor() { @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { - list.add(offset); - list.add(nextOffset); + list.add(new ControlFlowEdge(offset, nextOffset)); } @Override @@ -1361,34 +1377,7 @@ public class ControlFlowUtil { return null; } }, start, flow.getSize()); - BitSet violated = new BitSet(); - List instructions = flow.getInstructions(); - boolean changed = true; - while(changed) { - changed = false; - for(int i=list.size()-2; i>=0; i-=2) { - int from = list.get(i); - int to = list.get(i+1); - if(from == stop) continue; - if(violated.get(from)) { - if(!violated.get(to)) { - if(to == stop) return true; - violated.set(to); - changed = true; - } - continue; - } - Instruction instruction = instructions.get(from); - if((instruction instanceof ReadVariableInstruction && ((ReadVariableInstruction)instruction).variable == variable) || - (instruction instanceof WriteVariableInstruction && ((WriteVariableInstruction)instruction).variable == variable)) { - violated.set(from); - violated.set(to); - if(to == stop) return true; - changed = true; - } - } - } - return false; + return list; } /** diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollect.java new file mode 100644 index 000000000000..25f7274c3172 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollect.java @@ -0,0 +1,15 @@ +// "Replace with collect" "true" + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + List test(BufferedReader br) throws IOException { + List result; + result = br.lines().map(String::trim).collect(Collectors.toList()); + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollectNestedOk.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollectNestedOk.java new file mode 100644 index 000000000000..53c710fd73a3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderCollectNestedOk.java @@ -0,0 +1,19 @@ +// "Replace with collect" "true" + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + List test(List readers) throws IOException { + for(BufferedReader br : readers) { + List result; + result = br.lines().map(String::trim).collect(Collectors.toList()); + if(result.size() > 10) { + return result; + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderSum.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderSum.java new file mode 100644 index 000000000000..93c99a83b3e0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderSum.java @@ -0,0 +1,11 @@ +// "Replace with sum()" "true" + +import java.io.BufferedReader; +import java.io.IOException; + +public class Main { + void test(BufferedReader br) throws IOException { + long count = br.lines().map(String::trim).mapToLong(String::length).sum(); + System.out.println(count); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollect.java new file mode 100644 index 000000000000..23d877d08403 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollect.java @@ -0,0 +1,17 @@ +// "Replace with collect" "true" + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class Main { + List test(BufferedReader br) throws IOException { + List result = new ArrayList<>(); + String line = ""; + while(null != (line = br.readLine())) { + result.add(line.trim()); + } + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNested.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNested.java new file mode 100644 index 000000000000..6d050b10678d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNested.java @@ -0,0 +1,19 @@ +// "Replace with collect" "false" + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class Main { + List test(List readers) throws IOException { + List result = new ArrayList<>(); + for(BufferedReader br : readers) { + String line = ""; + while (null != (line = br.readLine())) { + result.add(line.trim()); + } + } + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNestedOk.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNestedOk.java new file mode 100644 index 000000000000..46d62990f876 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderCollectNestedOk.java @@ -0,0 +1,21 @@ +// "Replace with collect" "true" + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class Main { + List test(List readers) throws IOException { + for(BufferedReader br : readers) { + List result = new ArrayList<>(); + String line = ""; + while (null != (line = br.readLine())) { + result.add(line.trim()); + } + if(result.size() > 10) { + return result; + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java new file mode 100644 index 000000000000..dda6b3327432 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java @@ -0,0 +1,16 @@ +// "Replace with sum()" "false" + +import java.io.BufferedReader; +import java.io.IOException; + +public class Main { + void test(BufferedReader br) throws IOException { + String line = ""; + long count = 0; + while((line = br.readLine()) != null) { + line = line.trim(); + count+=line.length(); + } + System.out.println(count); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSum.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSum.java new file mode 100644 index 000000000000..d04658e420c8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSum.java @@ -0,0 +1,16 @@ +// "Replace with sum()" "true" + +import java.io.BufferedReader; +import java.io.IOException; + +public class Main { + void test(BufferedReader br) throws IOException { + String line = ""; + long count = 0; + while((line = br.readLine()) != null) { + String trimmed = line.trim(); + count+=trimmed.length(); + } + System.out.println(count); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSumLineReused.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSumLineReused.java new file mode 100644 index 000000000000..369771058f97 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderSumLineReused.java @@ -0,0 +1,16 @@ +// "Replace with sum()" "false" + +import java.io.BufferedReader; +import java.io.IOException; + +public class Main { + void test(BufferedReader br) throws IOException { + String line = ""; + long count = 0; + while((line = br.readLine()) != null) { + String trimmed = line.trim(); + count+=trimmed.length(); + } + System.out.println(count+":"+line); + } +} \ No newline at end of file diff --git a/resources-en/src/inspectionDescriptions/Convert2streamapi.html b/resources-en/src/inspectionDescriptions/Convert2streamapi.html index ff190f897875..3e2b1d886ea2 100644 --- a/resources-en/src/inspectionDescriptions/Convert2streamapi.html +++ b/resources-en/src/inspectionDescriptions/Convert2streamapi.html @@ -1,6 +1,6 @@ -This inspection reports foreach loops which can be replaced with stream API calls. +This inspection reports loops which can be replaced with stream API calls.

Stream API is not available under Java 1.7 or earlier JVMs. diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 8193fde74466..005b554bb44e 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -760,7 +760,7 @@ - Date: Fri, 21 Oct 2016 09:00:14 +0200 Subject: [PATCH 08/50] temporary fix for default project settings --- .../jetbrains/plugins/terminal/TerminalOptionsConfigurable.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalOptionsConfigurable.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalOptionsConfigurable.java index db7846fa7c60..f699ce8166cf 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalOptionsConfigurable.java +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalOptionsConfigurable.java @@ -61,6 +61,7 @@ public class TerminalOptionsConfigurable implements SearchableConfigurable, Conf @Override public JComponent createComponent() { myPanel = new TerminalSettingsPanel(); + if (myProjectOptionsProvider == null) return new JPanel(); return myPanel.createPanel(myOptionsProvider, myProjectOptionsProvider); } From 3df2d1925d50fd4c1e1c6de19cd465f5061fcfc4 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 21 Oct 2016 15:07:51 +0700 Subject: [PATCH 09/50] IDEA-162945 Stream API migration: support cases where variable is modified and reassigned --- .../StreamApiMigrationInspection.java | 77 ++++++++++++------- .../afterBufferedReaderModifiedLine.java | 11 +++ .../afterFilterMapFlatMapArrayMapCollect.java | 12 +++ ...foreBufferedReaderComplexModifiedLine.java | 15 ++++ .../beforeBufferedReaderModifiedLine.java | 2 +- ...beforeFilterMapFlatMapArrayMapCollect.java | 19 +++++ 6 files changed, 108 insertions(+), 28 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderModifiedLine.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFilterMapFlatMapArrayMapCollect.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderComplexModifiedLine.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFilterMapFlatMapArrayMapCollect.java diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java index e0506fa893ee..a837bc5ccb91 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java @@ -390,31 +390,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo return consumerClass != null ? psiFacade.getElementFactory().createType(consumerClass, variable.getType()) : null; } - static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement, StreamSource source) { - PsiElement declaration = variable.getParent(); - // For-loop initializer is not effectively final, but suitable for stream conversion - if(declaration instanceof PsiDeclarationStatement) { - PsiElement grandParent = declaration.getParent(); - if (grandParent instanceof PsiForStatement) { - PsiForStatement forStatement = (PsiForStatement)grandParent; - if (forStatement.getInitialization() == declaration) { - PsiStatement body = forStatement.getBody(); - if(body != null && PsiTreeUtil.isAncestor(statement, body, false)) { - return ReferencesSearch.search(variable, new LocalSearchScope(body)).forEach(ref -> { - PsiElement element = ref.getElement(); - return !(element instanceof PsiExpression) || !PsiUtil.isAccessedForWriting((PsiExpression)element); - }); - } - } - } - } - if(statement instanceof PsiWhileStatement && source.getVariable() == variable) { - return ReferencesSearch.search(variable, variable.getUseScope()).forEach(ref -> { - PsiElement element = ref.getElement(); - return !(element instanceof PsiExpression) || - PsiTreeUtil.isAncestor(((PsiWhileStatement)statement).getCondition(), element, false) || - !PsiUtil.isAccessedForWriting((PsiExpression)element); - }); + static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement, TerminalBlock tb) { + if(ReferencesSearch.search(variable, variable.getUseScope()).forEach(ref -> { + PsiElement element = ref.getElement(); + return !(element instanceof PsiExpression) || + !PsiUtil.isAccessedForWriting((PsiExpression)element) || + tb.operations().anyMatch(op -> op.isWriteAllowed(variable, (PsiExpression)element)); + })) { + return true; } return HighlightControlFlowUtil.isEffectivelyFinal(variable, statement, null); } @@ -590,7 +573,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo int startOffset = controlFlow.getStartOffset(body); int endOffset = controlFlow.getEndOffset(body); final List nonFinalVariables = StreamEx.of(ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset)) - .remove(variable -> isVariableSuitableForStream(variable, statement, source)).toList(); + .remove(variable -> isVariableSuitableForStream(variable, statement, tb)).toList(); if (exitPoints.isEmpty()) { if(getIncrementedVariable(tb, nonFinalVariables) != null) { @@ -902,6 +885,10 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } abstract String createReplacement(); + + boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) { + return false; + } } static class FilterOp extends Operation { @@ -993,6 +980,11 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo PsiExpression expression = myType == null ? myExpression : RefactoringUtil.convertInitializerToNormalExpression(myExpression, myType); return "." + operationName + "(" + LambdaUtil.createLambda(myVariable, expression) + ")"; } + + @Override + boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) { + return variable == myVariable && reference.getParent() == myExpression.getParent(); + } } static class FlatMapOp extends Operation { @@ -1026,6 +1018,11 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo return mySource.createReplacement(); } + @Override + boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) { + return mySource.isWriteAllowed(variable, reference); + } + boolean breaksMe(PsiBreakStatement statement) { return statement.findExitedStatement() == myLoop; } @@ -1070,6 +1067,11 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo myVariable.delete(); } + @Override + boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) { + return myVariable == variable && reference.getParent() == PsiTreeUtil.getParentOfType(myExpression, PsiAssignmentExpression.class); + } + @Nullable public static BufferedReaderLines from(PsiWhileStatement whileLoop) { // while ((line = br.readLine()) != null) @@ -1197,6 +1199,17 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo return className+"."+methodName+"("+myExpression.getText()+", "+myBound.getText()+")"; } + @Override + boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) { + if(variable == myVariable) { + PsiForStatement forStatement = PsiTreeUtil.getParentOfType(variable, PsiForStatement.class); + if(forStatement != null) { + return PsiTreeUtil.isAncestor(forStatement.getUpdate(), reference, false); + } + } + return false; + } + @Nullable public static CountingLoop from(PsiForStatement forStatement) { // check that initialization is for(int/long i = ;...;...) @@ -1402,6 +1415,16 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } } } + PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(first); + if(assignment != null) { + PsiExpression lValue = assignment.getLExpression(); + PsiExpression rValue = assignment.getRExpression(); + if(rValue != null && lValue instanceof PsiReferenceExpression && ((PsiReferenceExpression)lValue).isReferenceTo(myVariable)) { + PsiStatement[] leftOver = Arrays.copyOfRange(myStatements, 1, myStatements.length); + MapOp op = new MapOp(myPreviousOp, rValue, myVariable, myVariable.getType()); + return new TerminalBlock(op, myVariable, leftOver); + } + } } return null; } @@ -1434,7 +1457,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } @NotNull - private StreamEx operations() { + StreamEx operations() { return StreamEx.iterate(myPreviousOp, Objects::nonNull, Operation::getPreviousOp); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderModifiedLine.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderModifiedLine.java new file mode 100644 index 000000000000..93c99a83b3e0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterBufferedReaderModifiedLine.java @@ -0,0 +1,11 @@ +// "Replace with sum()" "true" + +import java.io.BufferedReader; +import java.io.IOException; + +public class Main { + void test(BufferedReader br) throws IOException { + long count = br.lines().map(String::trim).mapToLong(String::length).sum(); + System.out.println(count); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFilterMapFlatMapArrayMapCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFilterMapFlatMapArrayMapCollect.java new file mode 100644 index 000000000000..81e1b7dbcc44 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFilterMapFlatMapArrayMapCollect.java @@ -0,0 +1,12 @@ +// "Replace with collect" "true" +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class Main { + public void test(Map map) { + List result = map.entrySet().stream().filter(entry -> entry.getKey().startsWith("x")).map(Map.Entry::getValue).flatMap(Arrays::stream).map(String::trim).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderComplexModifiedLine.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderComplexModifiedLine.java new file mode 100644 index 000000000000..187dc491ef1b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderComplexModifiedLine.java @@ -0,0 +1,15 @@ +// "Replace with sum()" "false" + +import java.io.BufferedReader; +import java.io.IOException; + +public class Main { + void test(BufferedReader br) throws IOException { + String line = ""; + long count = 0; + while((line = br.readLine()) != null) { + count+=(line = line.trim()).length(); + } + System.out.println(count); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java index dda6b3327432..9b53dce87a23 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeBufferedReaderModifiedLine.java @@ -1,4 +1,4 @@ -// "Replace with sum()" "false" +// "Replace with sum()" "true" import java.io.BufferedReader; import java.io.IOException; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFilterMapFlatMapArrayMapCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFilterMapFlatMapArrayMapCollect.java new file mode 100644 index 000000000000..b994def8f9c0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFilterMapFlatMapArrayMapCollect.java @@ -0,0 +1,19 @@ +// "Replace with collect" "true" +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class Main { + public void test(Map map) { + List result = new ArrayList<>(); + for(Map.Entry entry: map.entrySet()) { + if(entry.getKey().startsWith("x")) { + String[] arr = entry.getValue(); + for (String str : arr) { + str = str.trim(); + result.add(str); + } + } + } + } +} \ No newline at end of file From f6325dc1a2bdc352fd0296acb7805277c41ba0da Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 21 Oct 2016 10:12:15 +0200 Subject: [PATCH 10/50] don't complain about frequent app.invokeLater calls since they don't lead to long (linear) peekEvent in AWT event queue fixes some log traces from IDEA-162047 --- .../com/intellij/openapi/application/impl/LaterInvocator.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java index d7773879c448..8cea4bf72e94 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java @@ -19,7 +19,6 @@ import com.intellij.ide.IdeEventQueue; import com.intellij.idea.IdeaApplication; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.*; -import com.intellij.openapi.diagnostic.FrequentEventDetector; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; @@ -55,7 +54,6 @@ public class LaterInvocator { private static final Object LOCK = new Object(); private static final IdeEventQueue ourEventQueue = IdeEventQueue.getInstance(); - private static final FrequentEventDetector ourFrequentEventDetector = new FrequentEventDetector(1009, 100); private LaterInvocator() { } @@ -146,8 +144,6 @@ public class LaterInvocator { @NotNull static ActionCallback invokeLater(@NotNull Runnable runnable, @NotNull ModalityState modalityState, @NotNull Condition expired) { - ourFrequentEventDetector.eventHappened(runnable); - final ActionCallback callback = new ActionCallback(); RunnableInfo runnableInfo = new RunnableInfo(runnable, modalityState, expired, callback); synchronized (LOCK) { From 68e3cd3e85af50f82b5c59f453ce568c99ea0837 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Thu, 20 Oct 2016 19:22:15 +0200 Subject: [PATCH 11/50] junit 5: for mixed junit 3 & 5 check inheritance if no annotations found (IDEA-162923) --- .../src/com/intellij/execution/junit/InheritorChooser.java | 5 ++--- .../impl/src/com/intellij/execution/junit/JUnitUtil.java | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java b/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java index 32519472d723..61d0172f3384 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java +++ b/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -35,7 +35,6 @@ import com.intellij.psi.util.PsiClassUtil; import com.intellij.ui.ColoredListCellRenderer; import com.intellij.ui.components.JBList; import com.intellij.util.ArrayUtil; -import com.intellij.util.Processor; import javax.swing.*; import java.util.ArrayList; @@ -85,7 +84,7 @@ public class InheritorChooser { if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> { final boolean isJUnit5 = ApplicationManager.getApplication().runReadAction((Computable)() -> JUnitUtil.isJUnit5(containingClass)); ClassInheritorsSearch.search(containingClass).forEach(aClass -> { - if (PsiClassUtil.isRunnableClass(aClass, !isJUnit5, true)) { + if (isJUnit5 && JUnitUtil.isJUnit5TestClass(aClass, true) || PsiClassUtil.isRunnableClass(aClass, true, true)) { classes.add(aClass); } return true; diff --git a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java index d63f2bc7bd4f..7ed83d254664 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java +++ b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -138,8 +138,8 @@ public class JUnitUtil { public static boolean isTestClass(@NotNull PsiClass psiClass, boolean checkAbstract, boolean checkForTestCaseInheritance) { if (psiClass.getQualifiedName() == null) return false; - if (isJUnit5(psiClass)) { - return isJUnit5TestClass(psiClass, checkAbstract); + if (isJUnit5(psiClass) && isJUnit5TestClass(psiClass, checkAbstract)) { + return true; } final PsiClass topLevelClass = PsiTreeUtil.getTopmostParentOfType(psiClass, PsiClass.class); if (topLevelClass != null) { From 7fb8e8e14ff03c4454e0cc58fa7cd64c1367b6e5 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 21 Oct 2016 10:30:12 +0200 Subject: [PATCH 12/50] increase timeout because our test agents are slow --- .../testSrc/org/jetbrains/concurrency/AsyncPromiseTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/platform-tests/testSrc/org/jetbrains/concurrency/AsyncPromiseTest.kt b/platform/platform-tests/testSrc/org/jetbrains/concurrency/AsyncPromiseTest.kt index 2aead477e5fe..aedb1530838b 100644 --- a/platform/platform-tests/testSrc/org/jetbrains/concurrency/AsyncPromiseTest.kt +++ b/platform/platform-tests/testSrc/org/jetbrains/concurrency/AsyncPromiseTest.kt @@ -66,9 +66,9 @@ class AsyncPromiseTest { fun blockingGet() { val promise = AsyncPromise() assertConcurrent( - { assertThat(promise.blockingGet(100)).isEqualTo("test") }, + { assertThat(promise.blockingGet(1000)).isEqualTo("test") }, { - Thread.sleep(80) + Thread.sleep(100) promise.setResult("test") }) } @@ -79,7 +79,7 @@ class AsyncPromiseTest { assertConcurrent( { assertThatThrownBy { promise.blockingGet(100) }.isInstanceOf(TimeoutException::class.java) }, { - Thread.sleep(200) + Thread.sleep(1000) promise.setResult("test") }) } @@ -142,7 +142,7 @@ fun assertConcurrent(vararg runnables: () -> Any?, maxTimeoutSeconds: Int = 5) { } // wait until all threads are ready - assertThat(allExecutorThreadsReady.await((runnables.size * 10).toLong(), TimeUnit.MILLISECONDS)).isTrue() + assertThat(allExecutorThreadsReady.await((runnables.size * 1000).toLong(), TimeUnit.MILLISECONDS)).isTrue() // start all test runners afterInitBlocker.countDown() assertThat(allDone.await(maxTimeoutSeconds.toLong(), TimeUnit.SECONDS)).isTrue() From 891f584cac32853d189d37ef1617863c22824afa Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Fri, 21 Oct 2016 12:16:28 +0300 Subject: [PATCH 13/50] IDEA-149511 Add jre64 to IDEA bundle IDEA-158522 Bundle 64-bit custom JDK on Windows or add an option to the installer to download it automatically IDEA-149164 Separate installers into 32 bit and 64 bit versions and bundle the appropriate JRE Changes in build scripts. --- .../build/IdeaCommunityProperties.groovy | 6 ++++ .../WindowsDistributionCustomizer.groovy | 8 +++++ .../build/impl/BundledJreManager.groovy | 2 +- .../build/impl/WinExeInstallerBuilder.groovy | 1 + .../impl/WindowsDistributionBuilder.groovy | 30 +++++++++++++++---- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/build/groovy/org/jetbrains/intellij/build/IdeaCommunityProperties.groovy b/build/groovy/org/jetbrains/intellij/build/IdeaCommunityProperties.groovy index 11a1fe8b19d9..1ee9b0fcd343 100644 --- a/build/groovy/org/jetbrains/intellij/build/IdeaCommunityProperties.groovy +++ b/build/groovy/org/jetbrains/intellij/build/IdeaCommunityProperties.groovy @@ -78,6 +78,12 @@ class IdeaCommunityProperties extends BaseIdeaProperties { String uninstallFeedbackPageUrl(ApplicationInfoProperties applicationInfo) { "https://www.jetbrains.com/idea/uninstall/?edition=IC-${applicationInfo.majorVersion}.${applicationInfo.minorVersion}" } + + @Override + String linkToJRE64(BuildContext buildContext) { + def versionString = buildContext.productProperties.baseArtifactName(buildContext.applicationInfo, buildContext.buildNumber) + return "https://download.jetbrains.com/idea/jre64-for-${versionString}.tar.gz" + } } } diff --git a/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy b/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy index 497ac852fc28..63641a9aa701 100644 --- a/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy +++ b/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy @@ -97,4 +97,12 @@ abstract class WindowsDistributionCustomizer { String uninstallFeedbackPageUrl(ApplicationInfoProperties applicationInfo) { return null } + + /** + * Link to a JetBrains JRE64 which is used by windows installation. + * JRE64 will be install (optional) together with JRE x86 (not replace). + */ + String linkToJRE64(BuildContext buildContext) { + return null + } } diff --git a/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy b/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy index b65bcf5638b5..0d6319b9b30a 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy @@ -98,7 +98,7 @@ class BundledJreManager { return targetDir } - private File findJreArchive(String osDirName, JvmArchitecture arch = JvmArchitecture.x64, JreVendor vendor = JreVendor.JetBrains) { + File findJreArchive(String osDirName, JvmArchitecture arch = JvmArchitecture.x64, JreVendor vendor = JreVendor.JetBrains) { def jdkDir = new File(buildContext.paths.projectHome, "build/jdk/$osDirName") String suffix = arch == JvmArchitecture.x32 ? "_x86" : "_x64" String prefix = buildContext.productProperties.toolsJarRequired ? vendor.jreWithToolsJarNamePrefix : vendor.jreNamePrefix diff --git a/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy index 9e14043862f7..bdd63baaaaeb 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy @@ -143,6 +143,7 @@ class WinExeInstallerBuilder { !define PRODUCT_HEADER_FILE "headerlogo.bmp" !define ASSOCIATION "$fileAssociations" !define UNINSTALL_WEB_PAGE "${customizer.uninstallFeedbackPageUrl(buildContext.applicationInfo) ?: "feedback_web_page"}" +!define LINK_TO_JRE64 "${customizer.linkToJRE64(buildContext)}" ; if SHOULD_SET_DEFAULT_INSTDIR != 0 then default installation directory will be directory where highest-numbered IDE build has been installed ; set to 1 for release build diff --git a/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy index efc5f29bd160..19d92d0b9752 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy @@ -82,14 +82,32 @@ class WindowsDistributionBuilder extends OsSpecificDistributionBuilder { void buildArtifacts(String winDistPath) { def arch = customizer.bundledJreArchitecture def jreDirectoryPath = arch != null ? buildContext.bundledJreManager.extractWinJre(arch) : null + List jreDirectoryPaths = [jreDirectoryPath]; + if (customizer.buildZipArchive) { - buildWinZip(jreDirectoryPath, buildContext.productProperties.buildCrossPlatformDistribution ? ".win" : "", winDistPath) + if (customizer.linkToJRE64(buildContext) != null && arch != JvmArchitecture.x64) { + File archive = buildContext.bundledJreManager.findJreArchive("win") + if (archive != null) { + //do copy of JRE64 archive + def versionString = buildContext.productProperties.baseArtifactName(buildContext.applicationInfo, buildContext.buildNumber) + buildContext.ant.copy(file: archive, tofile: "${buildContext.paths.artifacts}/jre64-for-${versionString}.tar.gz", overwrite: "true") + //prepare JRE64 folder for win archive + def jreDirectoryPath64 = buildContext.bundledJreManager.extractWinJre(JvmArchitecture.x64) + if (! new File("${jreDirectoryPath64}/jre64").exists()) { + buildContext.ant.move(todir: "${jreDirectoryPath64}/jre64") { + fileset(dir: "${jreDirectoryPath64}/jre") + } + } + jreDirectoryPaths = [jreDirectoryPath, jreDirectoryPath64]; + } + } + buildWinZip(jreDirectoryPaths, buildContext.productProperties.buildCrossPlatformDistribution ? ".win" : "", winDistPath) } if (arch != null && customizer.buildZipWithBundledOracleJre) { String oracleJrePath = buildContext.bundledJreManager.extractOracleWinJre(arch) if (oracleJrePath != null) { - buildWinZip(oracleJrePath, "-oracle-win", winDistPath) + buildWinZip([oracleJrePath], "-oracle-win", winDistPath) } else { buildContext.messages.warning("Skipping building Windows zip archive with bundled Oracle JRE because JRE archive is missing") @@ -208,13 +226,15 @@ IDS_VM_OPTIONS=$vmOptions } } - private void buildWinZip(String jreDirectoryPath, String zipNameSuffix, String winDistPath) { + private void buildWinZip(List jreDirectoryPaths, String zipNameSuffix, String winDistPath) { buildContext.messages.block("Build Windows ${zipNameSuffix}.zip distribution") { def targetPath = "$buildContext.paths.artifacts/${buildContext.productProperties.baseArtifactName(buildContext.applicationInfo, buildContext.buildNumber)}${zipNameSuffix}.zip" def zipPrefix = customizer.rootDirectoryName(buildContext.applicationInfo, buildContext.buildNumber) def dirs = [buildContext.paths.distAll, winDistPath] - if (jreDirectoryPath != null) { - dirs += jreDirectoryPath + if (jreDirectoryPaths != null) { + jreDirectoryPaths.each { + dirs += it + } } buildContext.messages.progress("Building Windows ${zipNameSuffix}.zip archive") buildContext.ant.zip(zipfile: targetPath) { From e040869958b96a12408554aafffe54508cdfa502 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 21 Oct 2016 11:21:39 +0200 Subject: [PATCH 14/50] remove unused code from LaterInvocator --- .../application/impl/LaterInvocator.java | 33 ++++++------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java index 8cea4bf72e94..e6e3e259b495 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java @@ -53,7 +53,6 @@ public class LaterInvocator { private static final boolean DEBUG = LOG.isDebugEnabled(); private static final Object LOCK = new Object(); - private static final IdeEventQueue ourEventQueue = IdeEventQueue.getInstance(); private LaterInvocator() { } @@ -92,8 +91,6 @@ public class LaterInvocator { private static volatile int ourQueueSkipCount; // optimization private static final FlushQueue ourFlushQueueRunnable = new FlushQueue(); - private static final Stack ourEventStack = new Stack<>(); // guarded by RUN_LOCK - private static final EventDispatcher ourModalityStateMulticaster = EventDispatcher.create(ModalityStateListener.class); public static void addModalityStateListener(@NotNull ModalityStateListener listener, @NotNull Disposable parentDisposable) { @@ -390,7 +387,6 @@ public class LaterInvocator { } private static final AtomicBoolean FLUSHER_SCHEDULED = new AtomicBoolean(false); - private static final Object RUN_LOCK = new Object(); private static class FlushQueue implements Runnable { @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized") private RunnableInfo myLastInfo; @@ -408,25 +404,16 @@ public class LaterInvocator { myLastInfo = lastInfo; if (lastInfo != null) { - synchronized (RUN_LOCK) { // necessary only because of switching to our own event queue - AWTEvent event = ourEventQueue.getTrueCurrentEvent(); - ourEventStack.push(event); - int stackSize = ourEventStack.size(); - - try { - lastInfo.runnable.run(); - lastInfo.callback.setDone(); - } - catch (ProcessCanceledException ignored) { } - catch (Throwable t) { - LOG.error(t); - } - finally { - LOG.assertTrue(ourEventStack.size() == stackSize); - ourEventStack.pop(); - - if (!DEBUG) myLastInfo = null; - } + try { + lastInfo.runnable.run(); + lastInfo.callback.setDone(); + } + catch (ProcessCanceledException ignored) { } + catch (Throwable t) { + LOG.error(t); + } + finally { + if (!DEBUG) myLastInfo = null; } } return lastInfo != null; From 38cca9aeec6df5412015a1fc76e5b7d1d7f7caad Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 21 Oct 2016 11:20:10 +0200 Subject: [PATCH 15/50] python profiler: don't create coverage view for profiler (PY-21170) --- .../com/intellij/coverage/CoverageDataManagerImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java index 2681d5da54de..302110e6ef31 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java +++ b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java @@ -115,7 +115,15 @@ public class CoverageDataManagerImpl extends CoverageDataManager { chooseSuitesBundle(myCurrentSuitesBundle); } }); - addSuiteListener(new CoverageViewSuiteListener(this, myProject), myProject); + final CoverageViewSuiteListener coverageViewListener = createCoverageViewListener(); + if (coverageViewListener != null) { + addSuiteListener(coverageViewListener, myProject); + } + } + + @Nullable + protected CoverageViewSuiteListener createCoverageViewListener() { + return new CoverageViewSuiteListener(this, myProject); } From 973630118099f4b784f2fcaf7a6c4e7b17e1f02a Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Fri, 21 Oct 2016 13:12:32 +0300 Subject: [PATCH 16/50] fixes after review IDEA-CR-14783 --- .../debugger/breakpoints/JavaBreakpointFiltersPanel.java | 3 +-- .../com/intellij/xdebugger/impl/XDebuggerUtilImpl.java | 4 ++-- .../impl/breakpoints/XBreakpointManagerImpl.java | 4 ++-- .../xdebugger/impl/breakpoints/XBreakpointUtil.java | 4 ++-- .../xdebugger/impl/breakpoints/ui/BreakpointsDialog.java | 5 ++--- .../breakpoints/ui/grouping/XBreakpointTypeGroup.java | 2 +- .../com/intellij/xdebugger/XDebuggerTestUtil.java | 9 ++++----- 7 files changed, 14 insertions(+), 17 deletions(-) diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java index 4a5bd3143b97..49f6ede26e1e 100644 --- a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java @@ -267,8 +267,7 @@ public class JavaBreakpointFiltersPanel s, String concator, int N, String NthConcator) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java index fda55327135a..3c759d4bb84f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java @@ -93,7 +93,7 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { @Override public XLineBreakpointType[] getLineBreakpointTypes() { if (myLineBreakpointTypes == null) { - myLineBreakpointTypes = XBreakpointUtil.getBreakpointTypes().select(XLineBreakpointType.class).toArray(XLineBreakpointType[]::new); + myLineBreakpointTypes = XBreakpointUtil.breakpointTypes().select(XLineBreakpointType.class).toArray(XLineBreakpointType[]::new); } return myLineBreakpointTypes; } @@ -289,7 +289,7 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { @Override public T findBreakpointType(@NotNull Class typeClass) { if (myBreakpointTypeByClass == null) { - myBreakpointTypeByClass = XBreakpointUtil.getBreakpointTypes().toMap(XBreakpointType::getClass, t -> t); + myBreakpointTypeByClass = XBreakpointUtil.breakpointTypes().toMap(XBreakpointType::getClass, t -> t); } XBreakpointType type = myBreakpointTypeByClass.get(typeClass); //noinspection unchecked diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java index 3329d22eebd1..63a63b84b54f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java @@ -75,7 +75,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta HttpVirtualFileListener httpVirtualFileListener = this::updateBreakpointInFile; HttpFileSystem.getInstance().addFileListener(httpVirtualFileListener, project); } - XBreakpointUtil.getBreakpointTypes().forEach(this::addDefaultBreakpoint); + XBreakpointUtil.breakpointTypes().forEach(this::addDefaultBreakpoint); } } @@ -397,7 +397,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta ApplicationManager.getApplication().runReadAction(() -> { state.getDefaultBreakpoints().forEach(breakpointState -> loadBreakpoint(breakpointState, true)); - XBreakpointUtil.getBreakpointTypes().remove(myDefaultBreakpoints::containsKey).forEach(this::addDefaultBreakpoint); + XBreakpointUtil.breakpointTypes().remove(myDefaultBreakpoints::containsKey).forEach(this::addDefaultBreakpoint); myBreakpoints.values().forEach(this::doRemoveBreakpoint); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java index 32b23e448ec9..b07d81d0c356 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java @@ -64,10 +64,10 @@ public class XBreakpointUtil { @Nullable public static XBreakpointType findType(@NotNull @NonNls String id) { - return getBreakpointTypes().filter(breakpointType -> id.equals(breakpointType.getId())).findFirst().orElse(null); + return breakpointTypes().filter(breakpointType -> id.equals(breakpointType.getId())).findFirst().orElse(null); } - public static StreamEx getBreakpointTypes() { + public static StreamEx breakpointTypes() { return StreamEx.of(XBreakpointType.EXTENSION_POINT_NAME.getExtensions()); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java index b62e50ff697f..720340dee108 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsDialog.java @@ -306,11 +306,10 @@ public class BreakpointsDialog extends DialogWrapper { } }.registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE).getShortcutSet(), tree, myDisposable); - DefaultActionGroup breakpointTypes = new DefaultActionGroup(); - XBreakpointUtil.getBreakpointTypes() + DefaultActionGroup breakpointTypes = XBreakpointUtil.breakpointTypes() .filter(XBreakpointType::isAddBreakpointButtonVisible) .map(AddXBreakpointAction::new) - .forEach(breakpointTypes::add); + .toListAndThen(DefaultActionGroup::new); ToolbarDecorator decorator = ToolbarDecorator.createDecorator(tree). setAddAction(new AnActionButtonRunnable() { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java index 1c490c7a4ce7..6eda5e3e026d 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/grouping/XBreakpointTypeGroup.java @@ -74,6 +74,6 @@ public class XBreakpointTypeGroup extends XBreakpointGroup { } private static int indexOfType(XBreakpointType type) { - return (int)XBreakpointUtil.getBreakpointTypes().indexOf(type).orElse(-1); + return (int)XBreakpointUtil.breakpointTypes().indexOf(type).orElse(-1); } } diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java index 85d35c0d14f9..9d133148b080 100644 --- a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java +++ b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java @@ -438,15 +438,14 @@ public class XDebuggerTestUtil { @NotNull final XBreakpointProperties properties) { XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); Ref breakpoint = Ref.create(null); - XBreakpointUtil.getBreakpointTypes().select(exceptionType).findFirst().ifPresent(type -> { - final T breakpointType = exceptionType.cast(type); + XBreakpointUtil.breakpointTypes().select(exceptionType).findFirst().ifPresent(type -> new WriteAction() { @Override protected void run(@NotNull Result result) throws Throwable { - breakpoint.set(breakpointManager.addBreakpoint(breakpointType, properties)); + breakpoint.set(breakpointManager.addBreakpoint(type, properties)); } - }.execute(); - }); + }.execute() + ); return breakpoint.get(); } From becf392833e65b0afb97ee0e496e8926931350bd Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Fri, 21 Oct 2016 13:14:38 +0300 Subject: [PATCH 17/50] don't restart background computation in AsyncEditorLoader if it's not in time for synchronous loading --- .../impl/text/AsyncEditorLoader.java | 168 +++++++++--------- .../impl/text/TextEditorComponent.java | 2 +- .../fileEditor/impl/text/TextEditorImpl.java | 2 +- 3 files changed, 82 insertions(+), 90 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java index 609204ff1942..559d9dd049b6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java @@ -20,12 +20,10 @@ import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.FileEditorStateLevel; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.progress.util.ProgressIndicatorUtils; -import com.intellij.openapi.progress.util.ReadTask; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; import com.intellij.openapi.wm.IdeFocusManager; @@ -36,20 +34,18 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; public class AsyncEditorLoader { - private static final ExecutorService ourExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor("AsyncEditorLoader pool",2); + private static final ExecutorService ourExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor("AsyncEditorLoader pool", 2); private static final Key ASYNC_LOADER = Key.create("ASYNC_LOADER"); + private static final int SYNCHRONOUS_LOADING_WAITING_TIME_MS = 200; + private static final int RETRY_TIME_MS = 10; @NotNull private final Editor myEditor; @NotNull private final Project myProject; @NotNull private final TextEditorImpl myTextEditor; @NotNull private final TextEditorComponent myEditorComponent; @NotNull private final TextEditorProvider myProvider; - private boolean myLoaded; private final List myDelayedActions = new ArrayList<>(); private TextEditorState myDelayedState; private final CompletableFuture myLoadingFinished = new CompletableFuture<>(); @@ -67,94 +63,90 @@ public class AsyncEditorLoader { } @NotNull - Future scheduleBackgroundLoading(boolean firstTime) { - ReadTask task = new ReadTask() { - PsiDocumentManager pdm = PsiDocumentManager.getInstance(myProject); - long startStamp = myEditor.getDocument().getModificationStamp(); - - @Override - public Continuation runBackgroundProcess(@NotNull ProgressIndicator indicator) throws ProcessCanceledException { - return pdm.commitAndRunReadAction(() -> { - if (myEditorComponent.isDisposed()) { - loadingFinished(); - return null; - } - - Runnable applyResults = myTextEditor.loadEditorInBackground(); - return new Continuation(() -> { - if (startStamp != myEditor.getDocument().getModificationStamp()) { - onCanceled(indicator); - return; - } - - try { - applyResults.run(); - } - finally { - loadingFinished(); - } - }, ModalityState.any()); - }); + Future start() { + ApplicationManager.getApplication().assertIsDispatchThread(); + Future continuationFuture = scheduleLoading(); + boolean showProgress = true; + if (worthWaiting()) { + /* + * Possible alternatives: + * 1. show "Loading" from the beginning, then it'll be always noticeable at least in fade-out phase + * 2. show a gray screen for some time and then "Loading" if it's still loading; it'll produce quick background blinking for all editors + * 3. show non-highlighted and unfolded editor as "Loading" background and allow it to relayout at the end of loading phase + * 4. freeze EDT a bit and hope that for small editors it'll suffice and for big ones show "Loading" after that. + * This strategy seems to produce minimal blinking annoyance. + */ + Runnable continuation = resultInTimeOrNull(continuationFuture, SYNCHRONOUS_LOADING_WAITING_TIME_MS); + if (continuation != null) { + showProgress = false; + loadingFinished(continuation); } - - @Override - public void onCanceled(@NotNull ProgressIndicator indicator) { - if (!myEditorComponent.isDisposed() && !myProject.isDisposed()) { - scheduleBackgroundLoading(false); - } - else { - loadingFinished(); - } - } - }; - - if (!firstTime || !loadImmediately(task)) { - myEditorComponent.startLoading(); - ProgressIndicatorUtils.scheduleWithWriteActionPriority(new ProgressIndicatorBase(), ourExecutor, task); } + if (showProgress) myEditorComponent.startLoading(); return myLoadingFinished; } - /** - * Possible alternatives: - * 1. show "Loading" from the beginning, then it'll be always noticeable at least in fade-out phase - * 2. show a gray screen for some time and then "Loading" if it's still loading; it'll produce quick background blinking for all editors - * 3. show non-highlighted and unfolded editor as "Loading" background and allow it to relayout at the end of loading phase - * 4. freeze EDT a bit and hope that for small editors it'll suffice and for big ones show "Loading" after that. - * This strategy seems to produce minimal blinking annoyance. - */ - private boolean loadImmediately(@NotNull ReadTask task) { - if (PsiDocumentManager.getInstance(myProject).hasUncommitedDocuments() || - ApplicationManager.getApplication().isWriteAccessAllowed()) { - return false; // cannot perform commitAndRunReadAction in parallel to EDT waiting - } - - ProgressIndicatorBase indicator = new ProgressIndicatorBase(); - Future future = ourExecutor.submit(() -> { - Ref continuationRef = Ref.create(); - ProgressIndicatorUtils.runWithWriteActionPriority(() -> continuationRef.set(task.runBackgroundProcess(indicator)), indicator); - return continuationRef.get(); - }); - try { - ReadTask.Continuation applyImmediately = future.get(200, TimeUnit.MILLISECONDS); - if (applyImmediately != null) { - applyImmediately.getAction().run(); - return true; + private Future scheduleLoading() { + PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(myProject); + long startStamp = myEditor.getDocument().getModificationStamp(); + return ourExecutor.submit(() -> { + Ref ref = new Ref<>(); + while (!myEditorComponent.isDisposed()) { + ProgressIndicatorUtils.runWithWriteActionPriority( + () -> ref.set(psiDocumentManager.commitAndRunReadAction(() -> myProject.isDisposed() ? EmptyRunnable.INSTANCE + : myTextEditor.loadEditorInBackground())), + new ProgressIndicatorBase() + ); + Runnable continuation = ref.get(); + if (continuation != null) { + invokeLater(() -> { + if (startStamp == myEditor.getDocument().getModificationStamp()) loadingFinished(continuation); + else if (!myProject.isDisposed() && !myEditorComponent.isDisposed()) scheduleLoading(); + }); + return continuation; + } + TimeUnit.MILLISECONDS.sleep(RETRY_TIME_MS); } - } - catch (Exception ignored) { - } - - indicator.cancel(); - return false; + invokeLater(() -> loadingFinished(null)); + return null; + }); } - private void loadingFinished() { + private static void invokeLater(Runnable runnable) { + ApplicationManager.getApplication().invokeLater(runnable, ModalityState.any()); + } + + private boolean worthWaiting() { + // cannot perform commitAndRunReadAction in parallel to EDT waiting + return !PsiDocumentManager.getInstance(myProject).hasUncommitedDocuments() && + !ApplicationManager.getApplication().isWriteAccessAllowed(); + } + + private static T resultInTimeOrNull(Future future, long timeMs) { + try { + return future.get(timeMs, TimeUnit.MILLISECONDS); + } + catch (InterruptedException | TimeoutException ignored) {} + catch (ExecutionException e) { + throw new RuntimeException(e); + } + return null; + } + + private void loadingFinished(Runnable continuation) { + if (myLoadingFinished.isDone()) return; myLoadingFinished.complete(null); myEditor.putUserData(ASYNC_LOADER, null); - myLoaded = true; + if (myEditorComponent.isDisposed()) return; - myEditorComponent.stopLoading(); + + if (continuation != null) { + continuation.run(); + } + + if (myEditorComponent.isLoading()) { + myEditorComponent.stopLoading(); + } myEditorComponent.getContentPanel().setVisible(true); if (myDelayedState != null) { @@ -193,7 +185,7 @@ public class AsyncEditorLoader { TextEditorState state = myProvider.getStateImpl(myProject, myEditor, level); - if (!myLoaded && myDelayedState != null) { + if (!myLoadingFinished.isDone() && myDelayedState != null) { state.setDelayedFoldState(myDelayedState::getFoldingState); } return state; @@ -202,7 +194,7 @@ public class AsyncEditorLoader { void setEditorState(@NotNull final TextEditorState state) { ApplicationManager.getApplication().assertIsDispatchThread(); - if (!myLoaded) { + if (!myLoadingFinished.isDone()) { myDelayedState = state; } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java index ba10f60288bb..8b72201801f5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorComponent.java @@ -120,7 +120,7 @@ class TextEditorComponent extends JBLoadingPanel implements DataProvider { }); } - private boolean myDisposed; + private volatile boolean myDisposed; /** * Disposes all resources allocated be the TextEditorComponent. It disposes all created * editors, unregisters listeners. The behaviour of the splitter after disposing is diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java index e952ec52758c..9e0b99a0a4e9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java @@ -57,7 +57,7 @@ public class TextEditorImpl extends UserDataHolderBase implements TextEditor { myChangeSupport = new PropertyChangeSupport(this); myComponent = createEditorComponent(project, file); myAsyncLoader = new AsyncEditorLoader(this, myComponent, provider); - myLoadingFinished = myAsyncLoader.scheduleBackgroundLoading(true); + myLoadingFinished = myAsyncLoader.start(); } @NotNull From 3ebc95151fd7d2f39f049e39a49616faf68f8d9f Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 21 Oct 2016 12:15:11 +0200 Subject: [PATCH 18/50] remove unused IgnoreDocumentRunnable --- .../com/intellij/openapi/editor/DocumentRunnable.java | 5 ----- .../codeInsight/daemon/impl/DaemonListeners.java | 9 --------- .../codeInsight/daemon/impl/PsiChangeHandler.java | 2 +- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/platform/core-api/src/com/intellij/openapi/editor/DocumentRunnable.java b/platform/core-api/src/com/intellij/openapi/editor/DocumentRunnable.java index 8b2133775564..e1b242090965 100644 --- a/platform/core-api/src/com/intellij/openapi/editor/DocumentRunnable.java +++ b/platform/core-api/src/com/intellij/openapi/editor/DocumentRunnable.java @@ -38,9 +38,4 @@ public abstract class DocumentRunnable implements Runnable { return myProject; } - public abstract static class IgnoreDocumentRunnable extends DocumentRunnable { - public IgnoreDocumentRunnable() { - super(null, null); - } - } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java index ce40d42eee2c..a0d2939c9cc9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java @@ -173,7 +173,6 @@ public class DaemonListeners implements Disposable { // clearing highlighters before changing document because change can damage editor highlighters drastically, so we'll clear more than necessary @Override public void beforeDocumentChange(final DocumentEvent e) { - if (isUnderIgnoredAction(null)) return; Document document = e.getDocument(); VirtualFile virtualFile = fileDocumentManager.getFile(document); Project project = virtualFile == null ? null : ProjectUtil.guessProjectForFile(virtualFile); @@ -348,12 +347,6 @@ public class DaemonListeners implements Disposable { } } - static boolean isUnderIgnoredAction(@Nullable Object action) { - return action instanceof DocumentRunnable.IgnoreDocumentRunnable || - action == DocumentRunnable.IgnoreDocumentRunnable.class || - ApplicationManager.getApplication().hasWriteAction(DocumentRunnable.IgnoreDocumentRunnable.class); - } - private boolean worthBothering(final Document document, Project project) { if (document == null) return true; if (project != null && project != myProject) return false; @@ -432,7 +425,6 @@ public class DaemonListeners implements Disposable { @Override public void commandStarted(CommandEvent event) { Document affectedDocument = extractDocumentFromCommand(event); - if (isUnderIgnoredAction(null)) return; if (!worthBothering(affectedDocument, event.getProject())) return; cutOperationJustHappened = myCutActionName.equals(event.getCommandName()); @@ -461,7 +453,6 @@ public class DaemonListeners implements Disposable { @Override public void commandFinished(CommandEvent event) { Document affectedDocument = extractDocumentFromCommand(event); - if (isUnderIgnoredAction(null)) return; if (!worthBothering(affectedDocument, event.getProject())) return; if (myEscPressed) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java index 01869a0c205d..0c8d509ff8e5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java @@ -104,7 +104,7 @@ class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable { private void updateChangesForDocument(@NotNull final Document document) { ApplicationManager.getApplication().assertIsDispatchThread(); - if (DaemonListeners.isUnderIgnoredAction(null) || myProject.isDisposed()) return; + if (myProject.isDisposed()) return; List> toUpdate = changedElements.get(document); if (toUpdate == null) { // The document has been changed, but psi hasn't From 903c6d9b1ebddec5550b9c775953a01443ad9d4e Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Fri, 21 Oct 2016 12:18:05 +0200 Subject: [PATCH 19/50] [performance] on Windows, list jar archives with handle to original file (instead of handle to its copy). The motivation is to delay initial synchronous jar copy creation until we start to read content from this jar file. --- .../intellij/openapi/vfs/impl/ZipHandler.java | 63 +++++++++++++------ .../openapi/vfs/impl/jar/JarHandler.java | 7 ++- .../openapi/vfs/local/JarFileSystemTest.java | 21 +++++++ 3 files changed, 72 insertions(+), 19 deletions(-) diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java index 0363d8a1b8a3..8db15107dc1a 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java @@ -48,9 +48,7 @@ public class ZipHandler extends ArchiveHandler { @Override protected ZipFile createAccessor(ZipHandler key) throws IOException { final String canonicalPathToZip = key.getCanonicalPathToZip(); - FileAttributes attributes = FileSystemUtil.getAttributes(canonicalPathToZip); - key.myFileStamp = attributes != null ? attributes.lastModified : DEFAULT_TIMESTAMP; - key.myFileLength = attributes != null ? attributes.length : DEFAULT_LENGTH; + setFileStampAndLength(key, canonicalPathToZip); return new ZipFile(canonicalPathToZip); } @@ -67,6 +65,13 @@ public class ZipHandler extends ArchiveHandler { } }; + private static synchronized void setFileStampAndLength(ZipHandler zipHandler, String pathToZip) { + FileAttributes attributes = FileSystemUtil.getAttributes(pathToZip); + + zipHandler.myFileStamp = attributes != null ? attributes.lastModified : DEFAULT_TIMESTAMP; + zipHandler.myFileLength = attributes != null ? attributes.length : DEFAULT_LENGTH; + } + @NotNull private String getCanonicalPathToZip() throws IOException { String value = myCanonicalPathToZip; @@ -79,30 +84,52 @@ public class ZipHandler extends ArchiveHandler { @NotNull @Override protected Map createEntriesMap() throws IOException { - FileAccessorCache.Handle zipRef = getZipFileHandle(); - try { - ZipFile zip = zipRef.get(); + FileAccessorCache.Handle existingZipRef = getZipHandleForIteratingEntries(); - Map map = new ZipEntryMap(zip.size()); - map.put("", createRootEntry()); + if (existingZipRef == null) { + File file = getFile(); + ZipFile zipFile = new ZipFile(file); - Enumeration entries = zip.entries(); - while (entries.hasMoreElements()) { - getOrCreate(entries.nextElement(), map, zip); + setFileStampAndLength(this, file.getPath()); + try { + return buildEntryMapForZipFile(zipFile); } + finally { + zipFile.close(); + } + } - return map; + try { + return buildEntryMapForZipFile(existingZipRef.get()); } finally { - zipRef.release(); + existingZipRef.release(); } } - @NotNull - private FileAccessorCache.Handle getZipFileHandle() throws IOException { - FileAccessorCache.Handle handle = ourZipFileFileAccessorCache.get(this); + protected @Nullable FileAccessorCache.Handle getZipHandleForIteratingEntries() throws IOException { + return getCachedZipFileHandle(true); + } - if (getFile() == getFileToUse()) { // files are canonicalized + @NotNull + private Map buildEntryMapForZipFile(ZipFile zip) { + Map map = new ZipEntryMap(zip.size()); + map.put("", createRootEntry()); + + Enumeration entries = zip.entries(); + while (entries.hasMoreElements()) { + getOrCreate(entries.nextElement(), map, zip); + } + + return map; + } + + @Nullable + protected FileAccessorCache.Handle getCachedZipFileHandle(boolean createHandleIfNeeded) throws IOException { + FileAccessorCache.Handle handle = createHandleIfNeeded ? ourZipFileFileAccessorCache.get(this) : ourZipFileFileAccessorCache.getIfCached(this); + + // check handle is valid + if (handle != null && getFile() == getFileToUse()) { // files are canonicalized // IDEA-148458, http://bugs.java.com/view_bug.do?bug_id=4425695, JVM crashes on use of opened ZipFile after it was updated // Reopen file if the file has been changed FileAttributes attributes = FileSystemUtil.getAttributes(getCanonicalPathToZip()); @@ -200,7 +227,7 @@ public class ZipHandler extends ArchiveHandler { FileAccessorCache.Handle zipRef; try { - zipRef = getZipFileHandle(); + zipRef = getCachedZipFileHandle(true); } catch (RuntimeException ex) { Throwable cause = ex.getCause(); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java index 9eceb307cfd5..4c5c3023d062 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java @@ -45,6 +45,7 @@ import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; +import java.util.zip.ZipFile; /** * @author max @@ -56,7 +57,7 @@ public class JarHandler extends ZipHandler { private static final int FS_TIME_RESOLUTION = 2000; private final JarFileSystemImpl myFileSystem; - private volatile File myFileWithMirrorResolved; + private volatile File myFileWithMirrorResolved; // field is reflectively referenced in tests public JarHandler(@NotNull String path) { super(path); @@ -78,6 +79,10 @@ public class JarHandler extends ZipHandler { return fileWithMirrorResolved; } + protected @Nullable FileAccessorCache.Handle getZipHandleForIteratingEntries() throws IOException { + return getCachedZipFileHandle(!myFileSystem.isMakeCopyOfJar(getFile()) || myFileWithMirrorResolved != null); + } + private File getMirrorFile(@NotNull File originalFile) { if (!myFileSystem.isMakeCopyOfJar(originalFile)) return originalFile; diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java index 2a8bf039ebfa..462800fad254 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java @@ -18,8 +18,11 @@ package com.intellij.openapi.vfs.local; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileAttributes; import com.intellij.openapi.util.io.IoTestUtil; import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.impl.jar.JarFileSystemImpl; +import com.intellij.openapi.vfs.impl.jar.JarHandler; import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem; import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent; @@ -32,6 +35,7 @@ import org.junit.Test; import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.util.List; import java.util.jar.JarFile; @@ -117,6 +121,23 @@ public class JarFileSystemTest extends BareTestFixtureTestCase { assertContent(newEntry, "some text"); } + @Test + public void testJarHandlerDoNotCreateCopyWhenListingArchive() throws Exception { + File jar = IoTestUtil.createTestJar(); + JarHandler handler = new JarHandler(jar.getPath()); + FileAttributes attributes = handler.getAttributes(JarFile.MANIFEST_NAME); + assertTrue(attributes != null); + assertTrue(attributes.length == 0); + assertTrue(attributes.lastModified == jar.lastModified()); + + if (((JarFileSystemImpl)JarFileSystem.getInstance()).isMakeCopyOfJar(jar)) { + // for performance reasons we create file copy on windows when we read contents and have the handle open to the copy + Field resolved = handler.getClass().getDeclaredField("myFileWithMirrorResolved"); + resolved.setAccessible(true); + assertTrue(resolved.get(handler) == null); + } + } + @Test public void testInvalidJar() { String jarPath = PathManagerEx.getTestDataPath() + "/vfs/maven-toolchain-1.0.jar"; From a00320bc0c7a46cec188cf50d64d452c08905115 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Fri, 21 Oct 2016 12:22:41 +0200 Subject: [PATCH 20/50] more reliable skipping of non existing index ids when reading previous indexed state (EA-82338 - assert: IndexConfiguration.getIndex) --- .../src/com/intellij/util/indexing/IndexingStamp.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java index 879e761eab1c..5f76d4aa1631 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java @@ -22,6 +22,7 @@ import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.vfs.InvalidVirtualFileAccessException; import com.intellij.openapi.vfs.newvfs.FileAttribute; import com.intellij.openapi.vfs.newvfs.persistent.FSRecords; +import com.intellij.psi.stubs.StubIndexKey; import com.intellij.util.SmartList; import com.intellij.util.SystemProperties; import com.intellij.util.containers.ConcurrentIntObjectMap; @@ -198,7 +199,7 @@ public class IndexingStamp { while(stream.available() > 0) { ID id = ID.findById(DataInputOutputUtil.readINT(stream)); - if (id != null) { + if (id != null && !(id instanceof StubIndexKey)) { long stamp = getIndexCreationStamp(id); if (stamp == 0) continue; // All (indices) IDs should be valid in this running session (e.g. we can have ID instance existing but index is not registered) if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<>(5, 0.98f); @@ -209,7 +210,8 @@ public class IndexingStamp { if (outdatedIndices != null) { for(int outdatedIndexId:outdatedIndices) { ID id = ID.findById(outdatedIndexId); - if (id != null) { + if (id != null && !(id instanceof StubIndexKey)) { + if (getIndexCreationStamp(id) == 0) continue; // All (indices) IDs should be valid in this running session (e.g. we can have ID instance existing but index is not registered) long stamp = INDEX_DATA_OUTDATED_STAMP; if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<>(5, 0.98f); if (stamp <= dominatingIndexStamp) myIndexStamps.put(id, stamp); From 1cf3d5e56877c4b4ba6c391a4b54f3cd583d0742 Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Fri, 21 Oct 2016 13:30:59 +0300 Subject: [PATCH 21/50] Revert --- .../intellij/codeInsight/editorActions/BaseEnterHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BaseEnterHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BaseEnterHandler.java index c1971199c6c7..cbb701d8075c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BaseEnterHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BaseEnterHandler.java @@ -21,7 +21,7 @@ import com.intellij.openapi.editor.actionSystem.DocCommandGroupId; import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler; public abstract class BaseEnterHandler extends EditorWriteActionHandler { - public static final String GROUP_ID = "EnterHandler.GROUP_ID"; + private static final String GROUP_ID = "EnterHandler.GROUP_ID"; protected BaseEnterHandler() { super(false); From ce5abeeaaaf28a6e8a05c6fa1cd4b42292ccec75 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Fri, 21 Oct 2016 14:21:03 +0300 Subject: [PATCH 22/50] emulated method breakpoints: do not create exit breakpoints on throw for now --- .../com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java index 7ffb35d898c1..8380031b09dd 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java @@ -169,7 +169,7 @@ public class MethodBreakpoint extends BreakpointWithHighlighter l.lineNumber() == myLastLine) .findFirst().ifPresent(location -> createLocationBreakpointRequest(location, debugProcess)); From e912fbaf2fbe6cd57148594940b0a4588a203c4c Mon Sep 17 00:00:00 2001 From: Vyacheslav Karpukhin Date: Fri, 21 Oct 2016 12:27:49 +0200 Subject: [PATCH 23/50] Revert "Added AppLifecycleListener.appWilExit API" This reverts commit bc8f03f8ff44a15abbb93abec7dcb90bee0b24d5. --- .../src/com/intellij/ide/AppLifecycleListener.java | 5 ----- .../intellij/openapi/application/impl/ApplicationImpl.java | 4 +--- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/AppLifecycleListener.java b/platform/platform-impl/src/com/intellij/ide/AppLifecycleListener.java index 8adc41706d78..0dbb49745959 100644 --- a/platform/platform-impl/src/com/intellij/ide/AppLifecycleListener.java +++ b/platform/platform-impl/src/com/intellij/ide/AppLifecycleListener.java @@ -55,11 +55,6 @@ public interface AppLifecycleListener { */ void appClosing(); - /** - * Fired after all exit checks and after saving the settings. At this point the app is guaranteed to exit. - */ - default void appWillExit() { } - abstract class Adapter implements AppLifecycleListener { @Override public void appFrameCreated(String[] commandLineArgs, @NotNull Ref willOpenProject) { } diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index 2afffcfcf373..bf3580c55a03 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -758,8 +758,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App return; } - final AppLifecycleListener publisher = getMessageBus().syncPublisher(AppLifecycleListener.TOPIC); - publisher.appClosing(); + getMessageBus().syncPublisher(AppLifecycleListener.TOPIC).appClosing(); myDisposeInProgress = true; @@ -769,7 +768,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App saveSettings(); - publisher.appWillExit(); boolean success = disposeSelf(!force); if (!success || isUnitTestMode() || Boolean.getBoolean("idea.test.guimode")) { From 6c4f3549754114ed8cb40d65ea72d2e93877fb42 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Thu, 20 Oct 2016 18:25:54 +0300 Subject: [PATCH 24/50] [vcs]: (IDEA-162404) Commit details quick info font fixed --- .../src/com/intellij/dvcs/push/ui/VcsCommitInfoBalloon.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsCommitInfoBalloon.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsCommitInfoBalloon.java index 25796b054d17..0bda5ea5548c 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsCommitInfoBalloon.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsCommitInfoBalloon.java @@ -20,6 +20,7 @@ import com.intellij.ide.BrowserUtil; import com.intellij.openapi.ui.popup.ComponentPopupBuilder; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.vcs.history.VcsHistoryUtil; import com.intellij.ui.HyperlinkAdapter; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.awt.RelativePoint; @@ -51,7 +52,7 @@ public class VcsCommitInfoBalloon { myEditorPane.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE); myEditorPane.setEditable(false); myEditorPane.setBackground(HintUtil.INFORMATION_COLOR); - myEditorPane.setFont(UIUtil.getToolTipFont()); + myEditorPane.setFont(VcsHistoryUtil.getCommitDetailsFont()); myEditorPane.setBorder(HintUtil.createHintBorder()); Border margin = IdeBorderFactory.createEmptyBorder(3, 3, 3, 3); myEditorPane.setBorder(new CompoundBorder(myEditorPane.getBorder(), margin)); From e6c5ae94ba674fc2510148dd1a217e2c9e2fcbf1 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Thu, 20 Oct 2016 19:14:29 +0300 Subject: [PATCH 25/50] [patch]: (IDEA-162742) in Abort Applying dialog fix text presentation * use html underlined tag instead of braces; --- .../openapi/vcs/changes/patch/ApplyPatchAction.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java index 9bcb95c09861..aa7ba1c3c922 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java @@ -58,6 +58,7 @@ import com.intellij.util.Function; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcsUtil.VcsUtil; +import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.CalledInAwt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -241,9 +242,9 @@ public class ApplyPatchAction extends DumbAwareAction { @Override public boolean value(MergeTool.MergeViewer viewer) { int result = Messages.showYesNoCancelDialog(viewer.getComponent().getRootPane(), - "Would you like to (A)bort&Rollback applying patch action or (S)kip this file?", - "Close Merge", - "_Abort", "_Skip", "Cancel", Messages.getQuestionIcon()); + XmlStringUtil.wrapInHtml( + "Would you like to Abort&Rollback applying patch action or Skip this file?"), + "Close Merge", "_Abort", "_Skip", "Cancel", Messages.getQuestionIcon()); if (result == Messages.YES) { applyPatchStatusReference.set(ApplyPatchStatus.ABORT); From 0c04e878d4ede1b475a1f91d76975e5e0cd14b22 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Fri, 21 Oct 2016 14:52:53 +0300 Subject: [PATCH 26/50] [vcs]: cleanUp - update javadoc --- .../dvcs/repo/AsyncFilesManagerListener.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/repo/AsyncFilesManagerListener.java b/platform/dvcs-impl/src/com/intellij/dvcs/repo/AsyncFilesManagerListener.java index 480820128505..e642a67a48c9 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/repo/AsyncFilesManagerListener.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/repo/AsyncFilesManagerListener.java @@ -15,13 +15,19 @@ */ package com.intellij.dvcs.repo; +import com.intellij.openapi.vcs.changes.ChangeListManager; + import java.util.EventListener; /** - * The listener interface for handling async vcs files holder events. - * When a files holder model starts/finishes to update itself -> updateStarted/Finished will be called for all subscribers. - * e.g. vcs updates its ignored file model after that we should trigger ui update in ChangesView; + *

+ * The listener interface for handling async {@link ChangeListManager} node models updating. + *

+ *

+ * When model starts/finishes to update itself -> updateStarted/Finished will be called for all subscribers.
+ * e.g. vcs updates its ignored file model after that we should trigger ui update in ChangesView;
* moreover, when long duration update starts we should also trigger some action; + *

*/ public interface AsyncFilesManagerListener extends EventListener { From a46f1768b6240d6bb77cd538412f104112418052 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 21 Oct 2016 14:09:20 +0200 Subject: [PATCH 27/50] + drawDottedRectangle(Graphics, Rectangle) --- platform/util/src/com/intellij/util/ui/UIUtil.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 07f945c27351..7d5ddd12d8bd 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -1577,6 +1577,10 @@ public class UIUtil { sb.append(Integer.toHexString(color.getBlue())); } + public static void drawDottedRectangle(Graphics g, Rectangle r) { + drawDottedRectangle(g, r.x, r.y, r.x + r.width, r.y + r.height); + } + /** * @param g graphics. * @param x top left X coordinate. From 8530df9f34bb2a256088052f676d0a01ddb4a544 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 21 Oct 2016 14:10:56 +0200 Subject: [PATCH 28/50] don't hide paintFocus() method to DarculaRadioButtonUI --- .../ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java index 03f10fbf6f4a..15a2b6a5b583 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -168,6 +168,16 @@ public class DarculaRadioButtonUI extends MetalRadioButtonUI { mnemIndex, textRect.x, textRect.y + fm.getAscent()); } } + + if(b.hasFocus() && b.isFocusPainted() && + textRect.width > 0 && textRect.height > 0 ) { + paintFocus(g, textRect, b.getSize()); + } + } + + @Override + protected void paintFocus(Graphics g, Rectangle t, Dimension d) { + } @Override From 73fdbb6526bb8fe74e70867c47b19ab8e372479d Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 21 Oct 2016 14:11:34 +0200 Subject: [PATCH 29/50] dotted focus for win10 radio buttons --- .../ide/ui/laf/intellij/WinIntelliJRadioButtonUI.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJRadioButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJRadioButtonUI.java index 3fdf28bfb433..90a4d01efa86 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJRadioButtonUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJRadioButtonUI.java @@ -16,6 +16,7 @@ package com.intellij.ide.ui.laf.intellij; import com.intellij.ide.ui.laf.darcula.ui.DarculaRadioButtonUI; +import com.intellij.util.ui.UIUtil; import javax.swing.*; import javax.swing.plaf.ComponentUI; @@ -40,4 +41,12 @@ public class WinIntelliJRadioButtonUI extends DarculaRadioButtonUI { final int y = (viewRect.height - icon.getIconHeight()) / 2; icon.paintIcon(c, g, x, y); } + + @Override + protected void paintFocus(Graphics g, Rectangle t, Dimension d) { + g.setColor(getFocusColor()); + t.x -= 2; t.y -=1; + t.width += 3; t.height +=2; + UIUtil.drawDottedRectangle(g, t); + } } From cf9d8cd25b6070be3e3a7360c08f0038c7ea72f6 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 21 Oct 2016 14:27:02 +0200 Subject: [PATCH 30/50] setup proper AA settings for Event Log console --- .../src/com/intellij/notification/EventLogConsole.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java b/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java index 0790a2851f66..1e3542180493 100644 --- a/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java +++ b/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java @@ -35,6 +35,7 @@ import com.intellij.openapi.editor.colors.impl.DelegateColorScheme; import com.intellij.openapi.editor.event.EditorMouseEvent; import com.intellij.openapi.editor.ex.*; import com.intellij.openapi.editor.ex.util.EditorUtil; +import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.editor.markup.*; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; @@ -171,6 +172,9 @@ class EventLogConsole { } }); editor.setColorsScheme(ConsoleViewUtil.updateConsoleColorScheme(editor.createBoundColorSchemeDelegate(globalScheme))); + if (editor instanceof EditorImpl) { + ((EditorImpl)editor).setUseEditorAntialiasing(false); + } } private static DefaultActionGroup createPopupActions(ActionManager actionManager, From 8a276d0bf4379450c3d528a7c51dc43ae0cf28a1 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 21 Oct 2016 12:38:35 +0200 Subject: [PATCH 31/50] introduce variable: allow introduction of expression from inside for loop if independent from loop vars (IDEA-162911) --- .../IntroduceVariableBase.java | 22 +++++++++---------- ...LoopIndependantFromLoopVariable.after.java | 9 ++++++++ ...ideForLoopIndependantFromLoopVariable.java | 8 +++++++ .../refactoring/IntroduceVariableTest.java | 6 ++++- 4 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.after.java create mode 100644 java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.java diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index fa92d548a366..3b67150d9a5e 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -54,8 +54,6 @@ import com.intellij.psi.impl.source.jsp.jspJava.JspCodeBlock; import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil; -import com.intellij.psi.scope.processor.VariablesProcessor; -import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.util.*; import com.intellij.refactoring.*; import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer; @@ -755,14 +753,16 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { boolean skipForStatement = true; final PsiForStatement forStatement = PsiTreeUtil.getParentOfType(expr, PsiForStatement.class); if (forStatement != null) { - final VariablesProcessor variablesProcessor = new VariablesProcessor(false) { - @Override - protected boolean check(PsiVariable var, ResolveState state) { - return PsiTreeUtil.isAncestor(forStatement.getInitialization(), var, true); - } - }; - PsiScopesUtil.treeWalkUp(variablesProcessor, expr, null); - skipForStatement = variablesProcessor.size() == 0; + Set vars = new HashSet<>(); + SyntaxTraverser.psiTraverser().withRoot(expr) + .filter(element -> element instanceof PsiReferenceExpression) + .forEach(element -> { + final PsiElement resolve = ((PsiReferenceExpression)element).resolve(); + if (resolve instanceof PsiVariable) { + vars.add((PsiVariable)resolve); + } + }); + skipForStatement = vars.stream().noneMatch(variable -> PsiTreeUtil.isAncestor(forStatement.getInitialization(), variable, true)); } PsiElement containerParent = tempContainer; diff --git a/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.after.java b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.after.java new file mode 100644 index 000000000000..f8b362717c70 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.after.java @@ -0,0 +1,9 @@ +class Foo { + void foo(String[] input) { + int temp = input.length; + char[][] board = new char[temp][]; + for (int i = 0; i < temp; i++) { + System.out.println(temp); + } + } +} diff --git a/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.java b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.java new file mode 100644 index 000000000000..3d0a9a9e7523 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoopIndependantFromLoopVariable.java @@ -0,0 +1,8 @@ +class Foo { + void foo(String[] input) { + char[][] board = new char[input.length][]; + for (int i = 0; i < input.length; i++) { + System.out.println(input.length); + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java index eb7b18ed748f..f7da07c33723 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -207,6 +207,10 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { doTest(new MockIntroduceVariableHandler("temp", true, false, false, "int")); } + public void testInsideForLoopIndependantFromLoopVariable() { + doTest(new MockIntroduceVariableHandler("temp", true, false, false, "int")); + } + public void testDuplicateGenericExpressions() { doTest(new MockIntroduceVariableHandler("temp", true, false, false, "Foo2")); } From 260c6317c84462177800ec2d7c9ca66c35975d49 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 21 Oct 2016 14:50:42 +0200 Subject: [PATCH 32/50] inline local: go through lambda/inner class hierarchy evenly (IDEA-162909) --- .../intellij/refactoring/inline/InlineLocalHandler.java | 8 +++++--- .../inlineLocal/InlineVariableIntoNestedLambda.java | 6 ++++++ .../inlineLocal/InlineVariableIntoNestedLambda.java.after | 5 +++++ .../com/intellij/refactoring/inline/InlineLocalTest.java | 6 +++++- 4 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java create mode 100644 java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java.after diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java index e00821d3f98a..52f193742000 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -45,7 +45,9 @@ import com.intellij.refactoring.listeners.RefactoringEventData; import com.intellij.refactoring.listeners.RefactoringEventListener; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.InlineUtil; -import com.intellij.util.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.Query; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -96,7 +98,7 @@ public class InlineLocalHandler extends JavaInlineActionHandler { final PsiElement element = psiReference.getElement(); PsiElement innerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, PsiLambdaExpression.class); while (innerClass != containingClass && innerClass != null) { - final PsiClass parentPsiClass = PsiTreeUtil.getParentOfType(innerClass, PsiClass.class, true); + final PsiElement parentPsiClass = PsiTreeUtil.getParentOfType(innerClass.getParent(), PsiClass.class, PsiLambdaExpression.class); if (parentPsiClass == containingClass) { if (innerClass instanceof PsiLambdaExpression) { if (PsiTreeUtil.isAncestor(innerClass, local, false)) { diff --git a/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java b/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java new file mode 100644 index 000000000000..1ffb8ed7afae --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java @@ -0,0 +1,6 @@ +class Test { + { + String s = "hello"; + Runnable r = () -> {Runnable rr = () -> System.out.println(s);}; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java.after b/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java.after new file mode 100644 index 000000000000..bf51c648d5b8 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/InlineVariableIntoNestedLambda.java.after @@ -0,0 +1,5 @@ +class Test { + { + Runnable r = () -> {Runnable rr = () -> System.out.println("hello");}; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java index 6559b6bb6447..1bf326ee32c5 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -292,6 +292,10 @@ public class InlineLocalTest extends LightCodeInsightTestCase { "Variable 'hello' is accessed for writing"); } + public void testInlineVariableIntoNestedLambda() throws Exception { + doTest(false); + } + public void testAvoidTypeSpecificationWhenPossibleToAvoid() throws Exception { doTest(false); } From dcefbe431e10bbb407cd02550cc181f0db08134e Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Fri, 21 Oct 2016 16:07:51 +0300 Subject: [PATCH 33/50] Revert: Hide disabled and invisible actions from "Find Action..." result list --- .../intellij/ide/actions/GotoActionAction.java | 15 --------------- .../ide/util/gotoByName/ChooseByNameBase.java | 5 ----- 2 files changed, 20 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java index 4799415d79cb..1b4d89f9d706 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java @@ -55,7 +55,6 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.event.*; -import java.util.Iterator; import java.util.Set; public class GotoActionAction extends GotoActionBase implements DumbAware { @@ -98,20 +97,6 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { } final Disposable disposable = Disposer.newDisposable(); final ChooseByNamePopup popup = new ChooseByNamePopup(project, model, new GotoActionItemProvider(model), oldPopup, initialText, false, initialIndex) { - @Override - protected void filterInEDT(Set elements) { - for (Iterator iterator = elements.iterator(); iterator.hasNext(); ) { - Object o = iterator.next(); - if (o instanceof GotoActionModel.MatchedValue) { - Comparable value = ((GotoActionModel.MatchedValue)o).value; - if (value instanceof GotoActionModel.ActionWrapper) { - GotoActionModel.ActionWrapper wrapper = (GotoActionModel.ActionWrapper)value; - if (!wrapper.getPresentation().isEnabled() || !wrapper.getPresentation().isVisible()) iterator.remove(); - } - } - } - } - @Override protected void initUI(Callback callback, ModalityState modalityState, boolean allowMultipleSelection) { super.initUI(callback, modalityState, allowMultipleSelection); diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index 5bc6dca578d4..b71a4a021d3d 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -1467,9 +1467,6 @@ public abstract class ChooseByNameBase { return panel; } - protected void filterInEDT(Set elements) { - } - private class CalcElementsThread extends ReadTask { private final String myPattern; private final boolean myCheckboxState; @@ -1521,8 +1518,6 @@ public abstract class ChooseByNameBase { showCard(cardToShow, 0); - filterInEDT(filtered); - myCallback.consume(filtered); } }, myModalityState); From 79202bacb48f2b7c1e467ef1464dd31e8505f599 Mon Sep 17 00:00:00 2001 From: Alexander Koshevoy Date: Fri, 21 Oct 2016 16:13:57 +0300 Subject: [PATCH 34/50] PY-21183 Debugger state after accepting debugging script connection is connected --- .../debugger/pydev/transport/ServerModeDebuggerTransport.java | 1 + 1 file changed, 1 insertion(+) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/transport/ServerModeDebuggerTransport.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/transport/ServerModeDebuggerTransport.java index 74164e4f6f92..1494dea1614f 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/transport/ServerModeDebuggerTransport.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/transport/ServerModeDebuggerTransport.java @@ -39,6 +39,7 @@ public class ServerModeDebuggerTransport extends BaseDebuggerTransport { myServerSocket.setSoTimeout(myConnectionTimeout); Socket socket = myServerSocket.accept(); + myConnected = true; try { myDebuggerReader = new DebuggerReader(myDebugger, socket.getInputStream()); } From 34dfcb267875349b95f37304f9266cecbd60ba11 Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Fri, 21 Oct 2016 16:59:30 +0300 Subject: [PATCH 35/50] [dbe] honor DbSrcStorage.isEnabled() --- platform/util/resources/misc/registry.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 6449f11f07b5..12201700c919 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -743,9 +743,6 @@ database.scrollable.result.sets=true database.src_storage.enabled.description=Enables database sources storage database.src_storage.enabled.restartRequired=true database.src_storage.enabled=false -database.src_storage.writable.description=Enables database sources storage modification -database.src_storage.writable.restartRequired=true -database.src_storage.writable=false git.status.write=true git.blocking.read=true From fe5194680c577053dd1ee6c11db4ea48f00ab458 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 21 Oct 2016 17:00:03 +0300 Subject: [PATCH 36/50] IDEA-144000 toString() Generation Settings dialog hides fields due to missing vertical scroll bar --- .../com/intellij/openapi/options/TabbedConfigurable.java | 8 ++++++-- .../openapi/options/ex/ConfigurableCardPanel.java | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/options/TabbedConfigurable.java b/platform/platform-impl/src/com/intellij/openapi/options/TabbedConfigurable.java index 217339f748f0..59cde1bfc0e9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/TabbedConfigurable.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/TabbedConfigurable.java @@ -22,10 +22,13 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; +import static com.intellij.openapi.options.ex.ConfigurableCardPanel.createConfigurableComponent; + /** * @author yole */ -public abstract class TabbedConfigurable extends CompositeConfigurable { +public abstract class TabbedConfigurable extends CompositeConfigurable implements Configurable.NoScroll, + Configurable.NoMargin { protected TabbedPaneWrapper myTabbedPane; private final Disposable myParentDisposable; @@ -38,13 +41,14 @@ public abstract class TabbedConfigurable extends CompositeConfigurable() { @Override public JComponent compute() { From bd46384cdfed55b527a8b1ac4ad0ec63e477dbde Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Fri, 21 Oct 2016 16:45:50 +0300 Subject: [PATCH 37/50] minor cleanup --- .../ui/breakpoints/ExceptionBreakpoint.java | 8 +-- .../ui/breakpoints/FieldBreakpoint.java | 49 ++++++++----------- 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java index 40764bf435ff..d09979acea69 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java @@ -26,6 +26,7 @@ import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.*; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.intellij.debugger.engine.requests.RequestManagerImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; @@ -48,7 +49,6 @@ import com.sun.jdi.ObjectReference; import com.sun.jdi.ReferenceType; import com.sun.jdi.event.ExceptionEvent; import com.sun.jdi.event.LocatableEvent; -import com.sun.jdi.request.ExceptionRequest; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.java.debugger.breakpoints.properties.JavaExceptionBreakpointProperties; @@ -144,9 +144,9 @@ public class ExceptionBreakpoint extends Breakpoint Date: Fri, 21 Oct 2016 15:54:02 +0200 Subject: [PATCH 38/50] WI-33629 fixed bug: categorization of constant in Find Usage depends on the code location (cherry picked from commit ab870b87101a2d6c48c06e349c755bcfb4efa51e) --- .../core-api/src/com/intellij/usageView/UsageInfo.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/core-api/src/com/intellij/usageView/UsageInfo.java b/platform/core-api/src/com/intellij/usageView/UsageInfo.java index 25cdc3d2b166..2c2f3dc3be0c 100644 --- a/platform/core-api/src/com/intellij/usageView/UsageInfo.java +++ b/platform/core-api/src/com/intellij/usageView/UsageInfo.java @@ -107,7 +107,12 @@ public class UsageInfo { public UsageInfo(@NotNull PsiReference reference) { this(reference.getElement(), reference.getRangeInElement().getStartOffset(), reference.getRangeInElement().getEndOffset()); - myDynamicUsage = reference.resolve() == null; + if (reference instanceof PsiPolyVariantReference) { + myDynamicUsage = ((PsiPolyVariantReference)reference).multiResolve(false).length == 0; + } + else { + myDynamicUsage = reference.resolve() == null; + } } public UsageInfo(@NotNull PsiQualifiedReferenceElement reference) { From c0cb416a29d0fcd595a5499428d4284fd90cce97 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Fri, 21 Oct 2016 15:03:37 +0300 Subject: [PATCH 39/50] [Parameter Name Hints] Check if editor is EditorWindow, instead of editor.inlayModel is InlayModelImpl --- .../src/com/intellij/codeInsight/hints/PopupActions.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt b/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt index aec74685d04e..1d4e224bd6ab 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/hints/PopupActions.kt @@ -22,13 +22,12 @@ import com.intellij.codeInsight.hints.settings.ParameterNameHintsConfigurable import com.intellij.codeInsight.hints.settings.ParameterNameHintsSettings import com.intellij.codeInsight.intention.HighPriorityAction import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.injected.editor.EditorWindow import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.editor.Editor -import com.intellij.openapi.editor.InlayModel import com.intellij.openapi.editor.ex.EditorSettingsExternalizable -import com.intellij.openapi.editor.impl.InlayModelImpl import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectManager @@ -119,7 +118,7 @@ class ToggleInlineHintsAction : AnAction() { } private fun hasParameterHintAtOffset(editor: Editor, file: PsiFile): Boolean { - if (editor.inlayModel !is InlayModel) return false + if (editor is EditorWindow) return false val offset = editor.caretModel.offset val element = file.findElementAt(offset) @@ -127,7 +126,7 @@ private fun hasParameterHintAtOffset(editor: Editor, file: PsiFile): Boolean { val startOffset = element?.textRange?.startOffset ?: offset val endOffset = element?.textRange?.endOffset ?: offset - return editor.inlayModel is InlayModelImpl && editor.inlayModel + return editor.inlayModel .getInlineElementsInRange(startOffset, endOffset) .find { ParameterHintsPresentationManager.getInstance().isParameterHint(it) } != null } From dec08b85674b09465f5a8edd446c578d075a38bb Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Fri, 21 Oct 2016 16:37:49 +0300 Subject: [PATCH 40/50] [Parameter Name Hints] javadocs added --- .../hints/InlayParameterHintsProvider.kt | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/platform/lang-api/src/com/intellij/codeInsight/hints/InlayParameterHintsProvider.kt b/platform/lang-api/src/com/intellij/codeInsight/hints/InlayParameterHintsProvider.kt index 5e2f842039e7..6d9dc91dd9bd 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/hints/InlayParameterHintsProvider.kt +++ b/platform/lang-api/src/com/intellij/codeInsight/hints/InlayParameterHintsProvider.kt @@ -18,21 +18,34 @@ package com.intellij.codeInsight.hints import com.intellij.lang.Language import com.intellij.lang.LanguageExtension import com.intellij.psi.PsiElement +import org.jetbrains.annotations.ApiStatus object InlayParameterHintsExtension: LanguageExtension("com.intellij.parameterHintsProvider") +@ApiStatus.Experimental interface InlayParameterHintsProvider { - - fun getParameterHints(element: PsiElement): List { - return emptyList() - } - fun getMethodInfo(element: PsiElement): MethodInfo? { - return null - } - + /** + * Hints for params to be shown + */ + fun getParameterHints(element: PsiElement): List = emptyList() + + /** + * Provides fully qualified method name (e.g. "java.util.Map.put") and list of it's parameter names. + * Used when adding method to blacklist, when user invokes alt-enter on hint + * and selects "Do not show for this method". + */ + fun getMethodInfo(element: PsiElement): MethodInfo? = null + + /** + * Language used when saving blacklist methods + * Maybe will be moved to MethodInfo + */ val language: Language - + + /** + * Default list of methods for which hints should not be shown + */ val defaultBlackList: Set } From 8c849525c53c138662bebe5a7253953820bb1f94 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 21 Oct 2016 17:02:38 +0300 Subject: [PATCH 41/50] plugin management: pluginReplacement extension added and implemented for Google App Engine plugin It allows a plugin developer to specify that there is another plugin which replaces functionality of his plugin (IDEA-162974) --- .../ide/plugins/PluginReplacement.java | 64 +++++++++++++++++++ .../ide/plugins/InstallPluginAction.java | 2 +- .../intellij/ide/plugins/PluginInstaller.java | 39 ++++++++--- .../ide/plugins/PluginManagerMain.java | 29 ++++++++- .../PluginsAdvertiserDialog.java | 2 +- .../src/messages/IdeBundle.properties | 1 + .../src/META-INF/PlatformExtensionPoints.xml | 2 + .../META-INF/google-app-engine-plugin.xml | 2 + .../converter/AppEnginePluginReplacement.java | 27 ++++++++ 9 files changed, 155 insertions(+), 13 deletions(-) create mode 100644 platform/platform-api/src/com/intellij/ide/plugins/PluginReplacement.java create mode 100644 plugins/google-app-engine/source/com/intellij/appengine/converter/AppEnginePluginReplacement.java diff --git a/platform/platform-api/src/com/intellij/ide/plugins/PluginReplacement.java b/platform/platform-api/src/com/intellij/ide/plugins/PluginReplacement.java new file mode 100644 index 000000000000..4b274a14c772 --- /dev/null +++ b/platform/platform-api/src/com/intellij/ide/plugins/PluginReplacement.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2016 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.ide.plugins; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.extensions.PluginAware; +import com.intellij.openapi.extensions.PluginDescriptor; +import org.jetbrains.annotations.NotNull; + +/** + * Implement this class in your plugin if there is another plugin which functionality covers functionality provided by this plugin so there + * is no sense to have the both plugins installed together. This will instruct the IDE to suggest a user to disable this plugin when he + * downloads the new plugin in Settings | Plugins. + *

+ * The implementation must be registered in plugin.xml of the plugin you want to replace: + *

+ * <extensions defaultExtensionNs="com.intellij">
+ *   <pluginReplacement implementation="qualified-class-name"/>
+ * </extensions>
+ * 
+ * + * @author nik + */ +public abstract class PluginReplacement implements PluginAware { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.pluginReplacement"); + private final String myNewPluginId; + private PluginDescriptor myPluginDescriptor; + + protected PluginReplacement(String newPluginId) { + myNewPluginId = newPluginId; + } + + @NotNull + public String getReplacementMessage(@NotNull IdeaPluginDescriptor oldPlugin, @NotNull IdeaPluginDescriptor newPlugin) { + return "'" + newPlugin.getName() + "' plugin is designed as a replacement for currently installed '" + oldPlugin.getName() + "' plugin.
Do you want to " + + "disable '" + oldPlugin.getName() + "' to avoid possible conflicts?"; + } + + @Override + public final void setPluginDescriptor(PluginDescriptor pluginDescriptor) { + myPluginDescriptor = pluginDescriptor; + } + + public final PluginDescriptor getOldPluginDescriptor() { + return myPluginDescriptor; + } + + public final String getNewPluginId() { + return myNewPluginId; + } +} diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/InstallPluginAction.java b/platform/platform-impl/src/com/intellij/ide/plugins/InstallPluginAction.java index 2b40400a35da..21600f113bd3 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/InstallPluginAction.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/InstallPluginAction.java @@ -156,7 +156,7 @@ public class InstallPluginAction extends AnAction implements DumbAware { } }; final List plugins = myHost.getPluginsModel().getAllPlugins(); - PluginManagerMain.downloadPlugins(list, PluginManagerMain.mapToPluginIds(plugins), onInstallRunnable, cleanupRunnable); + PluginManagerMain.downloadPlugins(list, PluginManagerMain.mapToPluginIds(plugins), onInstallRunnable, pluginEnabler, cleanupRunnable); } catch (final IOException e1) { ourInstallingNodes.removeAll(list); diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java index 4f6d75a9d47c..6deff1df4851 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java @@ -20,6 +20,7 @@ import com.intellij.ide.startup.StartupActionScriptManager; import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.ex.ApplicationInfoEx; import com.intellij.openapi.extensions.PluginId; @@ -27,6 +28,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.updateSettings.impl.PluginDownloader; import com.intellij.openapi.updateSettings.impl.UpdateSettings; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.GuiUtils; import com.intellij.util.ArrayUtil; @@ -35,14 +37,12 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.ZipUtil; import com.intellij.util.ui.UIUtil; import gnu.trove.THashSet; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author stathik @@ -57,10 +57,11 @@ public class PluginInstaller { public static boolean prepareToInstall(List pluginsToInstall, List allPlugins, + PluginManagerMain.PluginEnabler pluginEnabler, @NotNull ProgressIndicator indicator) { updateUrls(pluginsToInstall, indicator); Set dependant = new THashSet<>(); - boolean install = prepareToInstall(pluginsToInstall, allPlugins, dependant, indicator); + boolean install = prepareToInstall(pluginsToInstall, allPlugins, dependant, pluginEnabler, indicator); for (PluginNode node : dependant) { if (!pluginsToInstall.contains(node)) { pluginsToInstall.add(node); @@ -110,6 +111,7 @@ public class PluginInstaller { private static boolean prepareToInstall(List pluginsToInstall, List allPlugins, Set installedDependant, + PluginManagerMain.PluginEnabler pluginEnabler, @NotNull ProgressIndicator indicator) { List pluginIds = new SmartList<>(); for (PluginNode pluginNode : pluginsToInstall) { @@ -120,7 +122,7 @@ public class PluginInstaller { for (PluginNode pluginNode : pluginsToInstall) { indicator.setText(pluginNode.getName()); try { - result |= prepareToInstall(pluginNode, pluginIds, allPlugins, installedDependant, indicator); + result |= prepareToInstall(pluginNode, pluginIds, allPlugins, installedDependant, pluginEnabler, indicator); } catch (IOException e) { String title = IdeBundle.message("title.plugin.error"); @@ -136,6 +138,7 @@ public class PluginInstaller { List pluginIds, List allPlugins, Set installedDependant, + PluginManagerMain.PluginEnabler pluginEnabler, @NotNull ProgressIndicator indicator) throws IOException { installedDependant.add(pluginNode); @@ -181,7 +184,7 @@ public class PluginInstaller { catch (Exception e) { return false; } - if (!proceed[0] || !prepareToInstall(depends, allPlugins, installedDependant, indicator)) { + if (!proceed[0] || !prepareToInstall(depends, allPlugins, installedDependant, pluginEnabler, indicator)) { return false; } } @@ -199,12 +202,29 @@ public class PluginInstaller { catch (Exception e) { return false; } - if (proceed[0] && !prepareToInstall(optionalDeps, allPlugins, installedDependant, indicator)) { + if (proceed[0] && !prepareToInstall(optionalDeps, allPlugins, installedDependant, pluginEnabler, indicator)) { return false; } } } + Ref toDisable = Ref.create(null); + Optional replacement = StreamEx.of(PluginReplacement.EP_NAME.getExtensions()) + .findFirst(r -> r.getNewPluginId().equals(pluginNode.getPluginId().getIdString())); + if (replacement.isPresent()) { + PluginReplacement pluginReplacement = replacement.get(); + IdeaPluginDescriptor oldPlugin = PluginManager.getPlugin(pluginReplacement.getOldPluginDescriptor().getPluginId()); + if (oldPlugin != null && !pluginEnabler.isDisabled(oldPlugin.getPluginId())) { + ApplicationManager.getApplication().invokeAndWait(() -> { + String title = IdeBundle.message("plugin.manager.obsolete.plugins.detected.title"); + String message = pluginReplacement.getReplacementMessage(oldPlugin, pluginNode); + if (Messages.showYesNoDialog(message, title, Messages.getWarningIcon()) == Messages.YES) { + toDisable.set(oldPlugin); + } + }); + } + } + PluginDownloader downloader = PluginDownloader.createDownloader(pluginNode, pluginNode.getRepositoryName(), null); if (downloader.prepareToInstall(indicator)) { @@ -212,6 +232,9 @@ public class PluginInstaller { downloader.install(); } pluginNode.setStatus(PluginNode.STATUS_DOWNLOADED); + if (!toDisable.isNull()) { + pluginEnabler.disablePlugins(Collections.singleton(toDisable.get())); + } } else { return false; diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java index 08ab7f1b8439..8188ae767b91 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java @@ -50,7 +50,6 @@ import com.intellij.ui.border.CustomLineBorder; import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.speedSearch.SpeedSearchSupply; -import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; @@ -408,17 +407,28 @@ public abstract class PluginManagerMain implements Disposable { loadPluginsFromHostInBackground(); } + /** + * @deprecated use {@link #downloadPlugins(List, List, Runnable, PluginEnabler, Runnable)} instead + */ public static boolean downloadPlugins(final List plugins, final List allPlugins, final Runnable onSuccess, @Nullable final Runnable cleanup) throws IOException { + return downloadPlugins(plugins, allPlugins, onSuccess, new PluginEnabler.HEADLESS(), cleanup); + } + + public static boolean downloadPlugins(final List plugins, + final List allPlugins, + final Runnable onSuccess, + PluginEnabler pluginEnabler, + @Nullable final Runnable cleanup) throws IOException { final boolean[] result = new boolean[1]; try { ProgressManager.getInstance().run(new Task.Backgroundable(null, IdeBundle.message("progress.download.plugins"), true, PluginManagerUISettings.getInstance()) { @Override public void run(@NotNull ProgressIndicator indicator) { try { - if (PluginInstaller.prepareToInstall(plugins, allPlugins, indicator)) { + if (PluginInstaller.prepareToInstall(plugins, allPlugins, pluginEnabler, indicator)) { ApplicationManager.getApplication().invokeLater(onSuccess); result[0] = true; } @@ -708,6 +718,7 @@ public abstract class PluginManagerMain implements Disposable { public interface PluginEnabler { void enablePlugins(Set disabled); + void disablePlugins(Set disabled); boolean isDisabled(PluginId pluginId); @@ -719,6 +730,13 @@ public abstract class PluginManagerMain implements Disposable { } } + @Override + public void disablePlugins(Set disabled) { + for (IdeaPluginDescriptor descriptor : disabled) { + PluginManagerCore.disablePlugin(descriptor.getPluginId().getIdString()); + } + } + @Override public boolean isDisabled(PluginId pluginId) { return isDisabled(pluginId.getIdString()); @@ -739,7 +757,12 @@ public abstract class PluginManagerMain implements Disposable { @Override public void enablePlugins(Set disabled) { - pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[disabled.size()]), true); + pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[0]), true); + } + + @Override + public void disablePlugins(Set disabled) { + pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[0]), false); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiserDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiserDialog.java index 2b049a3d1589..f2ffcf6f293e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiserDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiserDialog.java @@ -94,7 +94,7 @@ public class PluginsAdvertiserDialog extends DialogWrapper { } if (!nodes.isEmpty()) { try { - PluginManagerMain.downloadPlugins(nodes, myAllPlugins, notifyRunnable, null); + PluginManagerMain.downloadPlugins(nodes, myAllPlugins, notifyRunnable, pluginHelper, null); } catch (IOException e) { LOG.error(e); diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index e7acfaf1e55b..397ae57572b9 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -1034,6 +1034,7 @@ predefined.scope.production.name=Production plugin.manager.dependencies.detected.title=Plugin Dependencies Detected plugin.manager.dependencies.detected.message=The plugin you want to install requires other plugin{0, choice, 1#|2#s} ({1}) which have to be installed as well. Proceed? plugin.manager.optional.dependencies.detected.message=The plugin you want to install optionally requires other plugin{0, choice, 1#|2#s} ({1}). Should those be installed as well? +plugin.manager.obsolete.plugins.detected.title=Obsolete Plugins Detected message.server.no.licenses=No suitable licenses left on the license server title.server.no.licenses=No Licenses on Server message.server.not.available=Unable to contact license server diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 8733150897a1..125e5325347d 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -219,6 +219,8 @@ + + diff --git a/plugins/google-app-engine/resources/META-INF/google-app-engine-plugin.xml b/plugins/google-app-engine/resources/META-INF/google-app-engine-plugin.xml index 2d78b4f4cb0f..abe4b2d6ecf6 100644 --- a/plugins/google-app-engine/resources/META-INF/google-app-engine-plugin.xml +++ b/plugins/google-app-engine/resources/META-INF/google-app-engine-plugin.xml @@ -25,6 +25,8 @@ implementationClass="com.intellij.appengine.inspections.AppEngineForbiddenCodeInspection"/> + + diff --git a/plugins/google-app-engine/source/com/intellij/appengine/converter/AppEnginePluginReplacement.java b/plugins/google-app-engine/source/com/intellij/appengine/converter/AppEnginePluginReplacement.java new file mode 100644 index 000000000000..31dc1a4cb633 --- /dev/null +++ b/plugins/google-app-engine/source/com/intellij/appengine/converter/AppEnginePluginReplacement.java @@ -0,0 +1,27 @@ +/* + * Copyright 2000-2016 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.appengine.converter; + +import com.intellij.ide.plugins.PluginReplacement; + +/** + * @author nik + */ +public class AppEnginePluginReplacement extends PluginReplacement { + public AppEnginePluginReplacement() { + super("com.google.gct.core"); + } +} From ff2b75972f2ab2ea2c9a9dbeb39d65e35cd9875d Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 21 Oct 2016 17:37:37 +0300 Subject: [PATCH 42/50] javac ast indices: improve index update performance --- .../BackwardReferenceIndexWriter.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java index 3e6ca58caacc..d2bb308b8301 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java @@ -34,10 +34,7 @@ import org.jetbrains.jps.model.java.compiler.JavaCompilers; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; +import java.util.*; import static com.sun.tools.javac.code.Flags.PRIVATE; @@ -213,7 +210,23 @@ public class BackwardReferenceIndexWriter { private void updateHierarchyIndicesIncrementally(final CompilerBackwardReferenceIndex.LightDefinition classId, LightRef.JavaLightClassRef[] superIds) { final Collection rawOldSupers = myIndex.getHierarchyMap().get(classId); - Set oldSuperClasses = rawOldSupers == null ? null : new THashSet(rawOldSupers); + Set oldSuperClasses; + if (rawOldSupers == null) { + oldSuperClasses = null; + } + else { + if (superIds.length == rawOldSupers.size()) { + boolean needUpdate = false; + for (LightRef.JavaLightClassRef id : superIds) { + if (!rawOldSupers.contains(id)) { + needUpdate = true; + break; + } + } + if (!needUpdate) return; + } + oldSuperClasses = new THashSet(rawOldSupers); + } for (LightRef.JavaLightClassRef superId: superIds) { if (oldSuperClasses == null || !oldSuperClasses.remove(superId)) { myIndex.getBackwardHierarchyMap().put(superId, classId); From d7a338602e10ff486b5931328858993affeb2ce0 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 21 Oct 2016 17:46:59 +0300 Subject: [PATCH 43/50] javac ast indices: remove redundant forceEnabled option from index writer --- .../BackwardReferenceIndexBuilder.java | 6 +----- .../BackwardReferenceIndexWriter.java | 16 ++++++++++------ .../references/ReferenceIndexTestBase.kt | 7 ++----- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java index 931177aca9b2..97f8d642da6e 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java @@ -42,11 +42,7 @@ public class BackwardReferenceIndexBuilder extends ModuleLevelBuilder { @Override public void buildFinished(CompileContext context) { - final BackwardReferenceIndexWriter writer = BackwardReferenceIndexWriter.getInstance(); - if (writer != null) { - writer.close(); - } - BackwardReferenceIndexWriter.clearInstance(); + BackwardReferenceIndexWriter.closeIfNeed(); } @Override diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java index d2bb308b8301..991fa515c800 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java @@ -39,9 +39,7 @@ import java.util.*; import static com.sun.tools.javac.code.Flags.PRIVATE; public class BackwardReferenceIndexWriter { - public static final String PROP_KEY = "ref.index.builder"; - - public static volatile boolean forceEnabled; + public static final String PROP_KEY = "jps.backward.ref.index.builder"; private static volatile BackwardReferenceIndexWriter ourInstance; @@ -53,8 +51,14 @@ public class BackwardReferenceIndexWriter { myRebuild = rebuild; } - public static void clearInstance() { - ourInstance = null; + public static void closeIfNeed() { + if (ourInstance != null) { + try { + ourInstance.close(); + } finally { + ourInstance = null; + } + } } static BackwardReferenceIndexWriter getInstance() { @@ -85,7 +89,7 @@ public class BackwardReferenceIndexWriter { } public static boolean isEnabled() { - return SystemProperties.getBooleanProperty(PROP_KEY, false) || forceEnabled; + return SystemProperties.getBooleanProperty(PROP_KEY, false); } void close() { diff --git a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt index 2cdaac81f565..accc05100e94 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt +++ b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt @@ -31,16 +31,13 @@ import java.io.File abstract class ReferenceIndexTestBase : JpsBuildTestCase() { public override fun setUp() { - BackwardReferenceIndexWriter.forceEnabled = true super.setUp() -// System.setProperty(BackwardReferenceIndexWriter.PROP_KEY, true.toString()) + System.setProperty(BackwardReferenceIndexWriter.PROP_KEY, true.toString()) } public override fun tearDown() { super.tearDown() - BackwardReferenceIndexWriter.forceEnabled = false - BackwardReferenceIndexWriter.clearInstance() -// System.clearProperty(BackwardReferenceIndexWriter.PROP_KEY) + System.clearProperty(BackwardReferenceIndexWriter.PROP_KEY) } protected fun assertIndexOnRebuild(vararg files: String) { From b598cbe402971fcede7abcfcb6161c4be261ae1d Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 21 Oct 2016 18:03:40 +0300 Subject: [PATCH 44/50] javac ast indices: process removed files only if they exists --- .../backwardRefs/BackwardReferenceIndexBuilder.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java index 97f8d642da6e..adc3c626a660 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexBuilder.java @@ -50,11 +50,13 @@ public class BackwardReferenceIndexBuilder extends ModuleLevelBuilder { ModuleChunk chunk, DirtyFilesHolder dirtyFilesHolder, OutputConsumer outputConsumer) throws ProjectBuildException, IOException { - final BackwardReferenceIndexWriter writer = BackwardReferenceIndexWriter.getInstance(); - if (writer != null) { - for (ModuleBuildTarget target : chunk.getTargets()) { - final Collection files = dirtyFilesHolder.getRemovedFiles(target); - writer.processDeletedFiles(files); + if (dirtyFilesHolder.hasRemovedFiles()) { + final BackwardReferenceIndexWriter writer = BackwardReferenceIndexWriter.getInstance(); + if (writer != null) { + for (ModuleBuildTarget target : chunk.getTargets()) { + final Collection files = dirtyFilesHolder.getRemovedFiles(target); + writer.processDeletedFiles(files); + } } } return null; From 7ac40bd029c5a47923833afeab2a1f31a73de7e0 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 21 Oct 2016 17:12:32 +0200 Subject: [PATCH 45/50] some settings for Project View applied only on second attempt --- .../com/intellij/ide/projectView/impl/ProjectViewImpl.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 26000ab1b7c5..4e3ddf82294b 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -1409,9 +1409,8 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo for (String pane : myFlattenPackages.keySet()) { setPaneOption(myFlattenPackages, flattenPackages, pane, true); } - } else { - setPaneOption(myFlattenPackages, flattenPackages, paneId, true); } + setPaneOption(myFlattenPackages, flattenPackages, paneId, true); } public boolean isFoldersAlwaysOnTop() { @@ -1514,9 +1513,8 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo for (String pane : myHideEmptyPackages.keySet()) { setPaneOption(myHideEmptyPackages, hideEmptyPackages, pane, true); } - } else { - setPaneOption(myHideEmptyPackages, hideEmptyPackages, paneId, true); } + setPaneOption(myHideEmptyPackages, hideEmptyPackages, paneId, true); } @Override From 0ab414978b45cff7d4073e22fbe3740212971d9f Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Fri, 21 Oct 2016 18:16:12 +0300 Subject: [PATCH 46/50] Do not add indentation after XML prolog on Enter (WEB-6656 Cursor/Smart position is out of whack after ) --- xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java b/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java index e6a2fffc877c..7377d293f9d0 100644 --- a/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java +++ b/xml/impl/src/com/intellij/psi/formatter/xml/XmlBlock.java @@ -28,10 +28,7 @@ import com.intellij.psi.formatter.common.AbstractBlock; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.templateLanguages.OuterLanguageElement; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.xml.XmlDocument; -import com.intellij.psi.xml.XmlElementType; -import com.intellij.psi.xml.XmlTag; -import com.intellij.psi.xml.XmlTokenType; +import com.intellij.psi.xml.*; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -326,7 +323,7 @@ public class XmlBlock extends AbstractXmlBlock { @NotNull public ChildAttributes getChildAttributes(final int newChildIndex) { PsiElement element = myNode.getPsi(); - if (element instanceof PsiFile || element instanceof XmlDocument) { + if (element instanceof PsiFile || element instanceof XmlDocument || element instanceof XmlProlog) { return new ChildAttributes(Indent.getNoneIndent(), null); } else { From 2a4d33f2341b7d24a2782402921f84c285e9e8dc Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 21 Oct 2016 17:25:19 +0200 Subject: [PATCH 47/50] IDEA-161462: master password --- .../src/KeePassCredentialStore.kt | 15 +- .../src/PasswordSafeConfigurable.kt | 147 ++++++++++++++---- .../credential-store/src/PasswordSafeImpl.kt | 41 +++-- .../src/PasswordSafeSettings.java | 19 +-- .../src/PasswordSafeSettingsListener.java | 2 +- .../credential-store/src/dbV1Convertor.kt | 2 +- .../test/KeePassCredentialStoreTest.kt | 2 +- .../com/intellij/ui/layout/LayoutBuilder.kt | 12 ++ .../intellij/ui/layout/MigLayoutBuilder.kt | 78 ++++++++-- .../src/com/intellij/ui/layout/Row.kt | 12 +- .../src/com/intellij/ui/layout/layoutImpl.kt | 2 +- 11 files changed, 230 insertions(+), 102 deletions(-) diff --git a/platform/credential-store/src/KeePassCredentialStore.kt b/platform/credential-store/src/KeePassCredentialStore.kt index f373d1fcfd9f..e7ac517a9984 100644 --- a/platform/credential-store/src/KeePassCredentialStore.kt +++ b/platform/credential-store/src/KeePassCredentialStore.kt @@ -41,7 +41,7 @@ internal class KeePassCredentialStore(keyToValue: Map, store: PasswordStorage) { diff --git a/platform/credential-store/src/PasswordSafeConfigurable.kt b/platform/credential-store/src/PasswordSafeConfigurable.kt index 89292531183d..e6ead52b6438 100644 --- a/platform/credential-store/src/PasswordSafeConfigurable.kt +++ b/platform/credential-store/src/PasswordSafeConfigurable.kt @@ -15,16 +15,20 @@ */ package com.intellij.credentialStore -import com.intellij.credentialStore.PasswordSafeSettings.ProviderType import com.intellij.ide.passwordSafe.PasswordSafe import com.intellij.ide.passwordSafe.impl.PasswordSafeImpl +import com.intellij.ide.passwordSafe.impl.createPersistentCredentialStore import com.intellij.openapi.options.ConfigurableBase import com.intellij.openapi.options.ConfigurableUi import com.intellij.openapi.ui.Messages +import com.intellij.openapi.util.SystemInfo +import com.intellij.ui.components.JBPasswordField import com.intellij.ui.components.RadioButton import com.intellij.ui.layout.* import com.intellij.util.text.nullize +import gnu.trove.THashMap import java.awt.Component +import javax.swing.JPanel class PasswordSafeConfigurable(private val settings: PasswordSafeSettings) : ConfigurableBase("application.passwordSafe", "Passwords", "reference.ide.settings.password.safe") { override fun getSettings() = settings @@ -33,56 +37,139 @@ class PasswordSafeConfigurable(private val settings: PasswordSafeSettings) : Con } class PasswordSafeConfigurableUi : ConfigurableUi { - private val saveOnDisk = RadioButton("Save on &disk") - private val rememberPasswordsUntilClosing = RadioButton("Remember passwords &until the application is closed") + private val inKeychain = RadioButton("In Native Keychain") + + private val inKeePass = RadioButton("In KeePass") + private val keePassMasterPassword = JBPasswordField() + + private val rememberPasswordsUntilClosing = RadioButton("Do not save, forget passwords after restart") + + private val modeToRow = THashMap() override fun reset(settings: PasswordSafeSettings) { when (settings.providerType) { ProviderType.MEMORY_ONLY -> rememberPasswordsUntilClosing.isSelected = true - ProviderType.MASTER_PASSWORD -> saveOnDisk.isSelected = true + ProviderType.KEYCHAIN -> inKeychain.isSelected = true + ProviderType.KEEPASS -> inKeePass.isSelected = true else -> throw IllegalStateException("Unknown provider type: ${settings.providerType}") } + + updateEnabledState() } - override fun isModified(settings: PasswordSafeSettings) = getProviderType() != settings.providerType + override fun isModified(settings: PasswordSafeSettings): Boolean { + if (getProviderType() != settings.providerType) { + return true + } + + if (getProviderType() == ProviderType.KEEPASS && String(keePassMasterPassword.password).nullize(true) != null) { + return true + } + return false + } override fun apply(settings: PasswordSafeSettings) { - settings.providerType = getProviderType() + val providerType = getProviderType() + val passwordSafe = PasswordSafe.getInstance() as PasswordSafeImpl + var provider = passwordSafe.currentProvider + + val masterPassword = String(keePassMasterPassword.password).nullize(true)?.toByteArray() + + if (settings.providerType != providerType) { + @Suppress("NON_EXHAUSTIVE_WHEN") + when (providerType) { + ProviderType.MEMORY_ONLY -> { + if (provider is KeePassCredentialStore) { + provider.memoryOnly = true + provider.deleteFileStorage() + } + else { + provider = KeePassCredentialStore(memoryOnly = true) + } + } + + ProviderType.KEYCHAIN -> { + provider = createPersistentCredentialStore(provider as? KeePassCredentialStore) + } + + ProviderType.KEEPASS -> { + provider = KeePassCredentialStore(memoryOnly = true, existingMasterPassword = masterPassword) + } + } + } + + if (providerType == ProviderType.KEEPASS) { + if (provider === passwordSafe.currentProvider && masterPassword != null) { + // so, provider is the same and we must change master password for existing database file + (provider as KeePassCredentialStore).setMasterPassword(masterPassword) + } + } + + settings.providerType = providerType } - override fun getComponent() = panel { - val passwordSafe = PasswordSafe.getInstance() as PasswordSafeImpl + fun updateEnabledState() { + modeToRow[ProviderType.KEEPASS]?.enabled = getProviderType() == ProviderType.KEEPASS + } - buttonGroup { - row { - saveOnDisk() - if (!passwordSafe.isNativeCredentialStoreUsed) { - button("Set Master Password") { event -> - Messages.showInputDialog(event.source as Component, "Master Password:", "Set Master Password", null)?.trim().nullize()?.let { - passwordSafe.setFileDatabaseMasterPassword(it) - } + override fun getComponent(): JPanel { + val passwordSafe = PasswordSafe.getInstance() as PasswordSafeImpl + val currentProvider = passwordSafe.currentProvider + + keePassMasterPassword.setPasswordIsStored(true) + + val panel = panel { + row { label("Save passwords:") } + + buttonGroup({ updateEnabledState() }) { + if (SystemInfo.isLinux || isMacOsCredentialStoreSupported) { + row { + inKeychain() + } + } + + row { + inKeePass() + + modeToRow[ProviderType.KEEPASS] = row("Master Password:") { + keePassMasterPassword(growPolicy = GrowPolicy.SHORT_TEXT) + } + } + + row { + rememberPasswordsUntilClosing() + } + if (currentProvider is KeePassCredentialStore && !currentProvider.memoryOnly) { + row { hint("Existing KeePass file will be removed.") } + } + } + + if (!passwordSafe.isNativeCredentialStoreUsed) { + row(separated = true) { + button("Clear Passwords") { event -> + passwordSafe.clearPasswords() + Messages.showInfoMessage(event.source as Component, "Passwords were cleared", "Clear Passwords") } } } - row { rememberPasswordsUntilClosing() } } - if (!passwordSafe.isNativeCredentialStoreUsed) { - row(separated = true) { - button("Clear Passwords") { event -> - passwordSafe.clearPasswords() - Messages.showInfoMessage(event.source as Component, "Passwords were cleared", "Clear Passwords") - } - } - } + return panel } private fun getProviderType(): ProviderType { - if (rememberPasswordsUntilClosing.isSelected) { - return ProviderType.MEMORY_ONLY - } - else { - return ProviderType.MASTER_PASSWORD + return when { + rememberPasswordsUntilClosing.isSelected -> ProviderType.MEMORY_ONLY + inKeePass.isSelected -> ProviderType.KEEPASS + else -> ProviderType.KEYCHAIN } } +} + +internal enum class ProviderType { + MEMORY_ONLY, KEYCHAIN, KEEPASS, + + // unused, but we cannot remove it because enum value maybe stored in the config and we must correctly deserialize it + @Deprecated("") + DO_NOT_STORE } \ No newline at end of file diff --git a/platform/credential-store/src/PasswordSafeImpl.kt b/platform/credential-store/src/PasswordSafeImpl.kt index ee8a53d9c3f1..cad093d65074 100644 --- a/platform/credential-store/src/PasswordSafeImpl.kt +++ b/platform/credential-store/src/PasswordSafeImpl.kt @@ -18,7 +18,6 @@ package com.intellij.ide.passwordSafe.impl import com.intellij.credentialStore.* -import com.intellij.credentialStore.PasswordSafeSettings.ProviderType import com.intellij.ide.passwordSafe.PasswordSafe import com.intellij.ide.passwordSafe.PasswordStorage import com.intellij.openapi.application.ApplicationManager @@ -28,7 +27,7 @@ import org.jetbrains.concurrency.runAsync import java.nio.file.Path class PasswordSafeImpl(/* public - backward compatibility */val settings: PasswordSafeSettings) : PasswordSafe(), SettingsSavingComponent { - private @Volatile var currentProvider: PasswordStorage + internal @Volatile var currentProvider: PasswordStorage // it is helper storage to support set password as memory-only (see setPassword memoryOnly flag) private val memoryHelperProvider = lazy { KeePassCredentialStore(emptyMap(), memoryOnly = true) } @@ -45,25 +44,23 @@ class PasswordSafeImpl(/* public - backward compatibility */val settings: Passwo else { currentProvider = createPersistentCredentialStore() } + } - ApplicationManager.getApplication().messageBus.connect().subscribe(PasswordSafeSettings.TOPIC, object: PasswordSafeSettingsListener { - override fun typeChanged(oldValue: ProviderType, newValue: ProviderType) { - val memoryOnly = newValue == ProviderType.MEMORY_ONLY - if (memoryOnly) { - val provider = currentProvider - if (provider is KeePassCredentialStore) { - provider.memoryOnly = true - provider.deleteFileStorage() - } - else { - currentProvider = KeePassCredentialStore(memoryOnly = true) - } - } - else { - currentProvider = createPersistentCredentialStore(currentProvider as? KeePassCredentialStore) - } + internal fun setProvider(type: ProviderType) { + val memoryOnly = type == ProviderType.MEMORY_ONLY + if (memoryOnly) { + val provider = currentProvider + if (provider is KeePassCredentialStore) { + provider.memoryOnly = true + provider.deleteFileStorage() } - }) + else { + currentProvider = KeePassCredentialStore(memoryOnly = true) + } + } + else { + currentProvider = createPersistentCredentialStore(currentProvider as? KeePassCredentialStore) + } } override fun get(attributes: CredentialAttributes): Credentials? { @@ -122,9 +119,7 @@ class PasswordSafeImpl(/* public - backward compatibility */val settings: Passwo ApplicationManager.getApplication().messageBus.syncPublisher(PasswordSafeSettings.TOPIC).credentialStoreCleared() } - fun setFileDatabaseMasterPassword(password: String) { - (currentProvider as KeePassCredentialStore).setMasterPassword(password) - } + internal fun getKeePassCredentialStore() = currentProvider as KeePassCredentialStore fun importFileDatabase(path: Path, masterPassword: String) { currentProvider = copyFileDatabase(path, masterPassword) @@ -157,7 +152,7 @@ class PasswordSafeImpl(/* public - backward compatibility */val settings: Passwo get() = memoryHelperProvider.value } -private fun createPersistentCredentialStore(existing: KeePassCredentialStore? = null, convertFileStore: Boolean = false): PasswordStorage { +internal fun createPersistentCredentialStore(existing: KeePassCredentialStore? = null, convertFileStore: Boolean = false): PasswordStorage { LOG.catchAndLog { for (factory in CredentialStoreFactory.CREDENTIAL_STORE_FACTORY.extensions) { val store = factory.create() ?: continue diff --git a/platform/credential-store/src/PasswordSafeSettings.java b/platform/credential-store/src/PasswordSafeSettings.java index 080f8429ff57..8121e3b3397d 100644 --- a/platform/credential-store/src/PasswordSafeSettings.java +++ b/platform/credential-store/src/PasswordSafeSettings.java @@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull; public class PasswordSafeSettings implements PersistentStateComponent { public static final Topic TOPIC = Topic.create("PasswordSafeSettingsListener", PasswordSafeSettingsListener.class); - private ProviderType myProviderType = ProviderType.MASTER_PASSWORD; + private ProviderType myProviderType = ProviderType.KEYCHAIN; @NotNull public ProviderType getProviderType() { @@ -56,23 +56,10 @@ public class PasswordSafeSettings implements PersistentStateComponent Unit) { LayoutBuilder(`$`, ButtonGroup()).init() } + + inline fun buttonGroup(crossinline elementActionListener: () -> Unit, init: LayoutBuilder.() -> Unit): ButtonGroup { + val group = ButtonGroup() + LayoutBuilder(`$`, group).init() + + val listener = ActionListener { elementActionListener() } + for (button in group.elements) { + button.addActionListener(listener) + } + return group + } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt b/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt index c9b2d09fc8dd..e2c4b80395d4 100644 --- a/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt +++ b/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt @@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.ToggleAction import com.intellij.openapi.project.DumbAware import com.intellij.openapi.ui.OnePixelDivider import com.intellij.ui.SeparatorComponent +import com.intellij.ui.components.Label import com.intellij.ui.components.noteComponent import com.intellij.util.SmartList import net.miginfocom.layout.* @@ -40,14 +41,14 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { private val componentConstraints: MutableMap = SmartHashMap() - override fun newRow(label: JLabel?, buttonGroup: ButtonGroup?, separated: Boolean): Row { + override fun newRow(label: JLabel?, buttonGroup: ButtonGroup?, separated: Boolean, indented: Boolean): Row { if (separated) { - val row = MigLayoutRow(componentConstraints, noGrid = true, separated = true) + val row = MigLayoutRow(componentConstraints, this, noGrid = true, separated = true) rows.add(row) row.apply { SeparatorComponent(0, OnePixelDivider.BACKGROUND, null)() } } - val row = MigLayoutRow(componentConstraints, label != null, buttonGroup = buttonGroup) + val row = MigLayoutRow(componentConstraints, this, label != null, buttonGroup = buttonGroup, indented = indented) rows.add(row) label?.let { row.apply { label() } } @@ -59,13 +60,13 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { // add empty row as top gap newRow() - val row = MigLayoutRow(componentConstraints, noGrid = true) + val row = MigLayoutRow(componentConstraints, this, noGrid = true) rows.add(row) row.apply { noteComponent(text)() } } override fun build(container: Container, layoutConstraints: Array) { - val labeled = rows.firstOrNull(MigLayoutRow::labeled) != null + val labeled = rows.firstOrNull({ it.labeled && !it.indented }) != null var gapTop = -1 val lc = c() @@ -77,6 +78,8 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { lc.apply(layoutConstraints) } + lc.noVisualPadding() + container.layout = MigLayout(lc) val noGrid = layoutConstraints.contains(LCFlags.noGrid) @@ -124,12 +127,18 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { } else { var isSkippableComponent = true - if (component === row.components.first() && labeled) { - if (row.labeled) { - isSkippableComponent = false + if (component === row.components.first()) { + if (row.indented) { + cc.horizontal.gapBefore = gapToBoundSize(HORIZONTAL_GAP * 3, true) } - else { - cc.skip() + + if (labeled) { + if (row.labeled) { + isSkippableComponent = false + } + else { + cc.skip() + } } } @@ -138,7 +147,10 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { isSplitRequired = false cc.split() } - cc.horizontal.gapAfter = gapToBoundSize(HORIZONTAL_GAP * 2, true) + + if (component !== lastComponent) { + cc.horizontal.gapAfter = gapToBoundSize(HORIZONTAL_GAP * 2, true) + } } } @@ -166,20 +178,39 @@ private fun addGrowIfNeed(cc: CC, component: Component) { } } -private class MigLayoutRow(private val componentConstraints: MutableMap, val labeled: Boolean = false, val noGrid: Boolean = false, private val buttonGroup: ButtonGroup? = null, val separated: Boolean = false) : Row() { +private class MigLayoutRow(private val componentConstraints: MutableMap, + private val builder: MigLayoutBuilder, + val labeled: Boolean = false, + val noGrid: Boolean = false, + private val buttonGroup: ButtonGroup? = null, + val separated: Boolean = false, + val indented: Boolean = false) : Row() { val components = SmartList() var rightIndex = Int.MAX_VALUE - override operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int) { - addComponent(this, constraints, gapLeft = gapLeft) + override var enabled: Boolean = true + get() = field + set(value) { + if (field == value) { + return + } + + field = value + for (c in components) { + c.isEnabled = value + } + } + + override operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int, growPolicy: GrowPolicy?) { + addComponent(this, constraints, gapLeft = gapLeft, growPolicy = growPolicy) } - private fun addComponent(component: Component, constraints: Array, gapLeft: Int) { + private fun addComponent(component: Component, constraints: Array, gapLeft: Int, growPolicy: GrowPolicy?) { if (buttonGroup != null && component is JToggleButton) { buttonGroup.add(component) } - createComponentConstraints(constraints, gapLeft = gapLeft)?.let { + createComponentConstraints(constraints, gapLeft = gapLeft, growPolicy = growPolicy)?.let { componentConstraints.put(component, it) } components.add(component) @@ -191,6 +222,12 @@ private class MigLayoutRow(private val componentConstraints: MutableMap Unit): Row { + val row = builder.newRow(Label(label), indented = true) + row.init() + return row + } } private fun createComponentConstraints(constraints: Array? = null, @@ -198,7 +235,8 @@ private fun createComponentConstraints(constraints: Array? = null, gapAfter: Int = 0, gapTop: Int = 0, gapBottom: Int = 0, - split: Int = -1): CC? { + split: Int = -1, + growPolicy: GrowPolicy?): CC? { var _cc = constraints?.create() fun cc(): CC { if (_cc == null) { @@ -224,6 +262,12 @@ private fun createComponentConstraints(constraints: Array? = null, if (split != -1) { cc().split = split } + + if (growPolicy == GrowPolicy.SHORT_TEXT) { +// cc().minWidth("210") + cc().maxWidth("210") + } + return _cc } diff --git a/platform/platform-impl/src/com/intellij/ui/layout/Row.kt b/platform/platform-impl/src/com/intellij/ui/layout/Row.kt index 012acdb5efa4..9153addf4ed5 100644 --- a/platform/platform-impl/src/com/intellij/ui/layout/Row.kt +++ b/platform/platform-impl/src/com/intellij/ui/layout/Row.kt @@ -29,6 +29,8 @@ import javax.swing.JComponent import javax.swing.JLabel abstract class Row() { + abstract var enabled: Boolean + fun label(text: String, gapLeft: Int = 0, style: ComponentStyle? = null, fontColor: FontColor? = null, bold: Boolean = false) { Label(text, style, fontColor, bold)(gapLeft = gapLeft) } @@ -55,7 +57,7 @@ abstract class Row() { panel(*constraints) } - abstract operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int = 0) + abstract operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int = 0, growPolicy: GrowPolicy? = null) inline fun right(init: Row.() -> Unit) { alignRight() @@ -64,9 +66,7 @@ abstract class Row() { protected abstract fun alignRight() - @Deprecated(message = "Nested row is prohibited", level = DeprecationLevel.ERROR) - fun row(label: String, init: Row.() -> Unit) { - } + abstract fun row(label: String, init: Row.() -> Unit): Row @Deprecated(message = "Nested row is prohibited", level = DeprecationLevel.ERROR) fun row(label: JLabel? = null, init: Row.() -> Unit) { @@ -75,4 +75,8 @@ abstract class Row() { @Deprecated(message = "Nested noteRow is prohibited", level = DeprecationLevel.ERROR) fun noteRow(text: String) { } +} + +enum class GrowPolicy { + SHORT_TEXT } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/layout/layoutImpl.kt b/platform/platform-impl/src/com/intellij/ui/layout/layoutImpl.kt index a0aff8543335..f53366913449 100644 --- a/platform/platform-impl/src/com/intellij/ui/layout/layoutImpl.kt +++ b/platform/platform-impl/src/com/intellij/ui/layout/layoutImpl.kt @@ -32,7 +32,7 @@ fun createLayoutBuilder() = LayoutBuilder(MigLayoutBuilder()) // "When a protected member is accessed from an inline function, a public accessor method is created to provide an access to that protected member from the outside of the class where the function will be inlined to." // (https://youtrack.jetbrains.com/issue/KT-12215) interface LayoutBuilderImpl { - fun newRow(label: JLabel? = null, buttonGroup: ButtonGroup? = null, separated: Boolean = false): Row + fun newRow(label: JLabel? = null, buttonGroup: ButtonGroup? = null, separated: Boolean = false, indented: Boolean = false): Row fun build(container: Container, layoutConstraints: Array) From 3797d3ea1c2a039d687640170b74ac9e56a53cec Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 21 Oct 2016 17:27:56 +0200 Subject: [PATCH 48/50] ensure ambiguity error presentation doesn't depend on previous calls to getSubstitutor() --- .../daemon/impl/analysis/HighlightMethodUtil.java | 4 ++-- .../lambda/graphInference/OuterCallOverloads.java | 2 +- .../highlighting/AmbiguityReturnValueResolution3.java | 4 ++-- .../lambda/highlighting/AmbiguitySpecificReturn.java | 6 +++--- .../lambda/highlighting/ReturnTypeCompatibility.java | 2 +- .../lambda/mostSpecific/TargetTypeParameter.java | 2 +- .../lambda/newMethodRef/PotentialApplicability.java | 8 ++++---- .../PotentialCompatibilityWithInvalidShape.java | 2 +- .../overloadResolution/SpecificFunctionalInterfaces.java | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 9fc11002ed18..c7d1b15bd4cf 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -656,13 +656,13 @@ public class HighlightMethodUtil { if (methodCandidate2 != null) { PsiMethod element1 = methodCandidate1.getElement(); String m1 = PsiFormatUtil.formatMethod(element1, - methodCandidate1.getSubstitutor(), + methodCandidate1.getSubstitutor(false), PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_TYPE); PsiMethod element2 = methodCandidate2.getElement(); String m2 = PsiFormatUtil.formatMethod(element2, - methodCandidate2.getSubstitutor(), + methodCandidate2.getSubstitutor(false), PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_TYPE); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/OuterCallOverloads.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/OuterCallOverloads.java index 0b5b2b6f2812..6506a7a48464 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/OuterCallOverloads.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/OuterCallOverloads.java @@ -11,6 +11,6 @@ abstract class Overloadsss { { List l = foo(bar (null)); - List l1 = foo(bar1(null)); + List l1 = foo(bar1(null)); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java index 5f57240f5f0b..407d62494a00 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java @@ -8,8 +8,8 @@ class Test { IntStream mi = sp.map(Inner::foo); Stream mI = sp.map(Inner::fooBoxed); - IntStream li = sp.map(inner->inner.foo()); - Stream lI = sp.map(inner -> inner.fooBoxed()); + IntStream li = sp.map(inner->inner.foo()); + Stream lI = sp.map(inner -> inner.fooBoxed()); } interface Stream { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java index 291f7e2b0c91..3609928401e6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java @@ -1,8 +1,8 @@ class IntStream { private void foo(IntStream s) { - s.map(i -> 1 << i); - s.map(i -> 1); - s.map(i -> i); + s.map(i -> 1 << i); + s.map(i -> 1); + s.map(i -> i); } public static void main(String[] args) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java index 6ee3add7c1fe..6526c304cdde 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java @@ -25,7 +25,7 @@ class ReturnTypeIncompatibility { } public static void main(String[] args) { - call(i-> {return i;}); + call(i-> {return i;}); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/TargetTypeParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/TargetTypeParameter.java index 5b246569c17f..ee65e9cf26f3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/TargetTypeParameter.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/TargetTypeParameter.java @@ -3,7 +3,7 @@ import java.util.function.Supplier; class Test { public static void main(String... args) { - c(() -> 3, () -> 10); + c(() -> 3, () -> 10); } public static void c(Supplier s1, Supplier s2) {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java index 18f5026255c6..bda9f7270b74 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialApplicability.java @@ -31,8 +31,8 @@ class Test { String i1 = instanceCall(this::m0); String i2 = instanceCall(this::m1); String i3 = instanceCall(this::m2); - String i4 = instanceCall(this::m01); - String i5 = instanceCall(this::m012); + String i4 = instanceCall(this::m01); + String i5 = instanceCall(this::m012); } void n0() { } @@ -53,7 +53,7 @@ class Test { Test s1 = staticCall(Test::n0); Test s2 = staticCall(Test::n1); Test s3 = staticCall(Test::n2); - Test s4 = staticCall(Test::n01); - Test s5 = staticCall(Test::n012); + Test s4 = staticCall(Test::n01); + Test s5 = staticCall(Test::n012); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialCompatibilityWithInvalidShape.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialCompatibilityWithInvalidShape.java index 3cfa72c6ee2e..8b2cd92ac7a7 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialCompatibilityWithInvalidShape.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/PotentialCompatibilityWithInvalidShape.java @@ -34,7 +34,7 @@ class Test { { Set m = replyWith(this::query); System.out.println(m); - Set m1 = replyWith(this::query1); + Set m1 = replyWith(this::query1); System.out.println(m1); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/SpecificFunctionalInterfaces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/SpecificFunctionalInterfaces.java index 19ddda398cbf..b9db292d5346 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/SpecificFunctionalInterfaces.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/SpecificFunctionalInterfaces.java @@ -14,6 +14,6 @@ class Main { } { - perform(() -> {}); + perform(() -> {}); } } \ No newline at end of file From 9bcbdb68cbb2acaffa0720b38810dd52420b0161 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 21 Oct 2016 17:44:52 +0200 Subject: [PATCH 49/50] inference: register inference error when nested inference don't start as cached session already had errors --- .../src/com/intellij/psi/infos/MethodCandidateInfo.java | 6 +----- .../resolve/graphInference/InferenceSessionContainer.java | 6 ++++-- ...eckedConversionWasPerformedDuringApplicabilityCheck.java | 4 ++-- .../lambda/graphInference/HighlightArgumentWithProblem.java | 2 +- .../lambda/graphInference/IDEA128101.java | 6 +++--- .../CheckedExceptionsConstraintsSubstitutions1.java | 2 +- .../daemonCodeAnalyzer/lambda/newLambda/IDEA127215.java | 2 +- ...cludeConstraintsWhenParentMethodIsDuringCalculation.java | 5 +---- .../lambda/newMethodRef/UnresolvedMethodReference.java | 2 +- 9 files changed, 15 insertions(+), 20 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java index 3779effed5fe..13e3894493bb 100644 --- a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java +++ b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -305,10 +305,6 @@ public class MethodCandidateInfo extends CandidateInfo{ PsiSubstitutor substitutor = myCalcedSubstitutor; if (substitutor == null || !includeReturnConstraint && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) || isOverloadCheck()) { - if (includeReturnConstraint) { - myInferenceError = null; - } - PsiSubstitutor incompleteSubstitutor = super.getSubstitutor(); PsiMethod method = getElement(); if (myTypeArguments == null) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java index f46eeff51d99..3e96911dec34 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.resolve.graphInference; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy; import com.intellij.psi.impl.source.resolve.graphInference.constraints.ExpressionCompatibilityConstraint; @@ -140,7 +141,7 @@ public class InferenceSessionContainer { final PsiSubstitutor partialSubstitutor, @NotNull final PsiCall parent, @NotNull final ParameterTypeInferencePolicy policy, - final MethodCandidateInfo.CurrentCandidateProperties properties, + @NotNull final MethodCandidateInfo.CurrentCandidateProperties properties, final InferenceSession parentSession) { final CompoundInitialState compoundInitialState = createState(parentSession); InitialInferenceState initialInferenceState = compoundInitialState.getInitialState(parent); @@ -148,6 +149,7 @@ public class InferenceSessionContainer { final InferenceSession childSession = new InferenceSession(initialInferenceState); final List errorMessages = parentSession.getIncompatibleErrorMessages(); if (errorMessages != null) { + properties.getInfo().setInferenceError(StringUtil.join(errorMessages, "\n")); return childSession.prepareSubstitution(); } return childSession.collectAdditionalAndInfer(parameters, arguments, properties, compoundInitialState.getInitialSubstitutor()); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/EraseTypeForNewExpressionWithDiamondsIfUncheckedConversionWasPerformedDuringApplicabilityCheck.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/EraseTypeForNewExpressionWithDiamondsIfUncheckedConversionWasPerformedDuringApplicabilityCheck.java index be8587fc9bc6..169b53cdf0f3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/EraseTypeForNewExpressionWithDiamondsIfUncheckedConversionWasPerformedDuringApplicabilityCheck.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/EraseTypeForNewExpressionWithDiamondsIfUncheckedConversionWasPerformedDuringApplicabilityCheck.java @@ -6,10 +6,10 @@ class Test { Holder dataHolder = null; Result r3 = new Result<>(new Holder<>(dataHolder)); - Result r4 = Result.create(new Holder<>(dataHolder)); + Result r4 = Result.create(new Holder<>(dataHolder)); Result r5 = new Result<>(Holder.create(dataHolder)); - Result r6 = Result.create(Holder.create(dataHolder)); + Result r6 = Result.create(Holder.create(dataHolder)); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/HighlightArgumentWithProblem.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/HighlightArgumentWithProblem.java index 487a1abb7d0b..f50c9b15107a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/HighlightArgumentWithProblem.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/HighlightArgumentWithProblem.java @@ -7,6 +7,6 @@ class Test2 { } { - foo (bar(String.class), ""); + foo (bar(String.class), ""); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java index 2d4ff1af0738..f8fd21e75cce 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java @@ -20,10 +20,10 @@ class TestIDEA128101 { public static void test() { construct(String.class, createPath(integerAttribute), createPath(stringAttribute)); - construct1(String.class, createPath(integerAttribute), createPath(stringAttribute)); + construct1(String.class, createPath(integerAttribute), createPath(stringAttribute)); construct2(String.class, createPath(integerAttribute), createPath(stringAttribute)); - construct3(String.class, createPath(integerAttribute), createPath(stringAttribute)); - construct4(String.class, createPath(integerAttribute), createPath(stringAttribute)); + construct3(String.class, createPath(integerAttribute), createPath(stringAttribute)); + construct4(String.class, createPath(integerAttribute), createPath(stringAttribute)); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java index aff5ea6c4265..b905596c6c72 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java @@ -32,7 +32,7 @@ class Test1 { } { - bar(l -> baz(l)); + bar(l -> baz(l)); bar(this::baz); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA127215.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA127215.java index 226bdb51f9bf..b453df3c9264 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA127215.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA127215.java @@ -26,6 +26,6 @@ class Test { .map(object -> Arrays.stream(functions) .map(fn -> fn.apply(object)) .collect(toList())) - .collect(toList()); + .collect(toList()); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java index 7d5c0557acf7..98d7319d5ccf 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IncludeConstraintsWhenParentMethodIsDuringCalculation.java @@ -9,10 +9,7 @@ class Test { SuperFoo foo(I ax) { return null; } - SuperFoo ls = foo(() -> new Foo<>()); + SuperFoo ls = foo(() -> new Foo<>()); SuperFoo li = foo(() -> new Foo<>()); SuperFoo lw = foo(() -> new Foo<>()); } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/UnresolvedMethodReference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/UnresolvedMethodReference.java index 95219089de50..51d852826aff 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/UnresolvedMethodReference.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/UnresolvedMethodReference.java @@ -4,6 +4,6 @@ import java.util.Comparator; class Main { public void test() { - Collections.sort(new ArrayList<>(), Comparator::reversed); + Collections.sort(new ArrayList<>(), Comparator::reversed); } } \ No newline at end of file From ce87b2a8f8a0c3f6fd5852fc3a839138ae4caf81 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 21 Oct 2016 18:00:19 +0200 Subject: [PATCH 50/50] repeated tests: replace total with actual finished count --- .../intellij/execution/testframework/ui/TestStatusLine.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestStatusLine.java b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestStatusLine.java index ee296686647c..938fb80a7555 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestStatusLine.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestStatusLine.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -67,7 +67,7 @@ public class TestStatusLine extends JPanel { return; } String result = ""; - if (finishedTestsCount == testsTotal) { + if (finishedTestsCount == testsTotal || testsTotal < 0) { if (testsTotal > 1 && (failuresCount == 0 && ignoredTestsCount == 0 || failuresCount == testsTotal || ignoredTestsCount == testsTotal)) { result = "All "; } @@ -76,7 +76,7 @@ public class TestStatusLine extends JPanel { result = "Stopped. " + finishedTestsCount + " of "; } - result += getTestsTotalMessage(testsTotal); + result += getTestsTotalMessage(testsTotal > 0 ? testsTotal : finishedTestsCount); if (failuresCount == 0 && ignoredTestsCount == 0) { myState.append(result + " passed");